- Blood, Duke & SW: Create new backend chasecam function and replace game-specific versions with it.

* Based off SW's implementation.
This commit is contained in:
Mitchell Richters 2021-02-16 21:36:08 +11:00
parent 2abda0e27d
commit ba57429ac6
13 changed files with 172 additions and 270 deletions

View file

@ -1045,6 +1045,7 @@ set (PCH_SOURCES
core/gameconfigfile.cpp core/gameconfigfile.cpp
core/gamecvars.cpp core/gamecvars.cpp
core/gamecontrol.cpp core/gamecontrol.cpp
core/gamefuncs.cpp
core/gameinput.cpp core/gameinput.cpp
core/interpolate.cpp core/interpolate.cpp
core/inputstate.cpp core/inputstate.cpp

147
source/core/gamefuncs.cpp Normal file
View file

@ -0,0 +1,147 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2021 Christoph Oelckers & Mitchell Richters
This 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 the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "gamefuncs.h"
//---------------------------------------------------------------------------
//
// Unified chasecam function for all games.
//
//---------------------------------------------------------------------------
int cameradist, cameraclock;
bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnum, binangle ang, fixedhoriz horiz, double const smoothratio)
{
hitdata_t hitinfo;
binangle daang;
short bakcstat;
int newdist;
assert(*psectnum >= 0 && *psectnum < MAXSECTORS);
// Calculate new pos to shoot backwards, using averaged values from the big three.
int nx = xs_CRoundToInt(-ang.fcos() * (4352. / 3.));
int ny = xs_CRoundToInt(-ang.fsin() * (4352. / 3.));
int nz = xs_CRoundToInt(horiz.asq16() * (17. / 6144.));
vec3_t pvect = { *px, *py, *pz };
bakcstat = pspr->cstat;
pspr->cstat &= ~(CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN);
updatesectorz(*px, *py, *pz, psectnum);
hitscan(&pvect, *psectnum, nx, ny, nz, &hitinfo, CLIPMASK1);
pspr->cstat = bakcstat;
int hx = hitinfo.pos.x - *px;
int hy = hitinfo.pos.y - *py;
if (*psectnum < 0)
{
return false;
}
assert(*psectnum >= 0 && *psectnum < MAXSECTORS);
// If something is in the way, make pp->camera_dist lower if necessary
if (abs(nx) + abs(ny) > abs(hx) + abs(hy))
{
if (hitinfo.wall >= 0)
{
// Push you a little bit off the wall
*psectnum = hitinfo.sect;
daang = bvectangbam(wall[wall[hitinfo.wall].point2].x - wall[hitinfo.wall].x,
wall[wall[hitinfo.wall].point2].y - wall[hitinfo.wall].y);
newdist = nx * daang.bsin() + ny * -daang.bcos();
if (abs(nx) > abs(ny))
hx -= MulScale(nx, newdist, 28);
else
hy -= MulScale(ny, newdist, 28);
}
else if (hitinfo.sprite < 0)
{
// Push you off the ceiling/floor
*psectnum = hitinfo.sect;
if (abs(nx) > abs(ny))
hx -= (nx >> 5);
else
hy -= (ny >> 5);
}
else
{
// If you hit a sprite that's not a wall sprite - try again.
spritetype* hspr = &sprite[hitinfo.sprite];
if (!(hspr->cstat & CSTAT_SPRITE_ALIGNMENT_WALL))
{
bakcstat = hspr->cstat;
hspr->cstat &= ~(CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN);
calcChaseCamPos(px, py, pz, pspr, psectnum, ang, horiz, smoothratio);
hspr->cstat = bakcstat;
return false;
}
else
{
// same as wall calculation.
daang = buildang(pspr->ang - 512);
newdist = nx * daang.bsin() + ny * -daang.bcos();
if (abs(nx) > abs(ny))
hx -= MulScale(nx, newdist, 28);
else
hy -= MulScale(ny, newdist, 28);
}
}
if (abs(nx) > abs(ny))
newdist = DivScale(hx, nx, 16);
else
newdist = DivScale(hy, ny, 16);
if (newdist < cameradist)
cameradist = newdist;
}
// Actually move you! (Camerdist is 65536 if nothing is in the way)
*px += MulScale(nx, cameradist, 16);
*py += MulScale(ny, cameradist, 16);
*pz += MulScale(nz, cameradist, 16);
// Caculate clock using GameTicRate so it increases the same rate on all speed computers.
int myclock = PlayClock + MulScale(120 / GameTicRate, smoothratio, 16);
if (cameraclock == INT_MIN)
{
// Third person view was just started.
cameraclock = myclock;
}
// Slowly increase cameradist until it reaches 65536.
cameradist = min(cameradist + ((myclock - cameraclock) << 10), 65536);
cameraclock = myclock;
// Make sure psectnum is correct.
updatesectorz(*px, *py, *pz, psectnum);
return true;
}

9
source/core/gamefuncs.h Normal file
View file

@ -0,0 +1,9 @@
#pragma once
#include "gamecontrol.h"
#include "buildtypes.h"
#include "binaryangle.h"
extern int cameradist, cameraclock;
bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnum, binangle ang, fixedhoriz horiz, double const smoothratio);

View file

@ -40,6 +40,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "v_font.h" #include "v_font.h"
#include "statusbar.h" #include "statusbar.h"
#include "automap.h" #include "automap.h"
#include "gamefuncs.h"
#include "v_draw.h" #include "v_draw.h"
#include "glbackend/glbackend.h" #include "glbackend/glbackend.h"
@ -196,8 +197,7 @@ void viewInit(void)
} }
int othercameradist = 1280; int othercameradist = 1280;
int cameradist = -1; int othercameraclock;
int othercameraclock, cameraclock;
void CalcOtherPosition(spritetype *pSprite, int *pX, int *pY, int *pZ, int *vsectnum, int nAng, fixed_t zm, int smoothratio) void CalcOtherPosition(spritetype *pSprite, int *pX, int *pY, int *pZ, int *vsectnum, int nAng, fixed_t zm, int smoothratio)
{ {
@ -245,53 +245,6 @@ void CalcOtherPosition(spritetype *pSprite, int *pX, int *pY, int *pZ, int *vsec
pSprite->cstat = bakCstat; pSprite->cstat = bakCstat;
} }
void CalcPosition(spritetype *pSprite, int *pX, int *pY, int *pZ, int *vsectnum, int nAng, fixed_t zm, int smoothratio)
{
int vX = MulScale(-Cos(nAng), 1280, 30);
int vY = MulScale(-Sin(nAng), 1280, 30);
int vZ = FixedToInt(MulScale(zm, 1280, 3))-(16<<8);
int bakCstat = pSprite->cstat;
pSprite->cstat &= ~256;
assert(*vsectnum >= 0 && *vsectnum < kMaxSectors);
FindSector(*pX, *pY, *pZ, vsectnum);
short nHSector;
int hX, hY;
hitscangoal.x = hitscangoal.y = 0x1fffffff;
vec3_t pos = { *pX, *pY, *pZ };
hitdata_t hitdata;
hitscan(&pos, *vsectnum, vX, vY, vZ, &hitdata, CLIPMASK1);
nHSector = hitdata.sect;
hX = hitdata.pos.x;
hY = hitdata.pos.y;
int dX = hX-*pX;
int dY = hY-*pY;
if (abs(vX)+abs(vY) > abs(dX)+abs(dY))
{
*vsectnum = nHSector;
dX -= Sgn(vX)<<6;
dY -= Sgn(vY)<<6;
int nDist;
if (abs(vX) > abs(vY))
{
nDist = ClipHigh(DivScale(dX,vX, 16), cameradist);
}
else
{
nDist = ClipHigh(DivScale(dY,vY, 16), cameradist);
}
cameradist = nDist;
}
*pX += MulScale(vX, cameradist, 16);
*pY += MulScale(vY, cameradist, 16);
*pZ += MulScale(vZ, cameradist, 16);
int myclock = PlayClock + MulScale(4, smoothratio, 16);
cameradist = ClipHigh(cameradist+((myclock-cameraclock)<<10), 65536);
cameraclock = myclock;
assert(*vsectnum >= 0 && *vsectnum < kMaxSectors);
FindSector(*pX, *pY, *pZ, vsectnum);
pSprite->cstat = bakCstat;
}
// by NoOne: show warning msgs in game instead of throwing errors (in some cases) // by NoOne: show warning msgs in game instead of throwing errors (in some cases)
void viewSetSystemMessage(const char* pMessage, ...) { void viewSetSystemMessage(const char* pMessage, ...) {
char buffer[1024]; va_list args; va_start(args, pMessage); char buffer[1024]; va_list args; va_start(args, pMessage);
@ -633,11 +586,11 @@ void viewDrawScreen(bool sceneonly)
} }
cZ += xs_CRoundToInt(cH.asq16() / 6553.6); cZ += xs_CRoundToInt(cH.asq16() / 6553.6);
cameradist = -1; cameradist = -1;
cameraclock = PlayClock +MulScale(4, (int)gInterpolate, 16); cameraclock = PlayClock + MulScale(4, (int)gInterpolate, 16);
} }
else else
{ {
CalcPosition(gView->pSprite, (int*)&cX, (int*)&cY, (int*)&cZ, &nSectnum, cA.asbuild(), cH.asq16(), (int)gInterpolate); calcChaseCamPos((int*)&cX, (int*)&cY, (int*)&cZ, gView->pSprite, (short*)&nSectnum, cA, cH, gInterpolate);
} }
CheckLink((int*)&cX, (int*)&cY, (int*)&cZ, &nSectnum); CheckLink((int*)&cX, (int*)&cY, (int*)&cZ, &nSectnum);
int v78 = interpolateang(gScreenTiltO, gScreenTilt, gInterpolate); int v78 = interpolateang(gScreenTiltO, gScreenTilt, gInterpolate);

View file

@ -34,6 +34,7 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
#include "cheathandler.h" #include "cheathandler.h"
#include "c_dispatch.h" #include "c_dispatch.h"
#include "gamestate.h" #include "gamestate.h"
#include "gamefuncs.h"
#include "dukeactor.h" #include "dukeactor.h"
BEGIN_DUKE_NS BEGIN_DUKE_NS

View file

@ -126,7 +126,6 @@ void playerLookUp(int snum, ESyncBits actions);
void playerLookDown(int snum, ESyncBits actions); void playerLookDown(int snum, ESyncBits actions);
void playerAimUp(int snum, ESyncBits actions); void playerAimUp(int snum, ESyncBits actions);
void playerAimDown(int snum, ESyncBits actions); void playerAimDown(int snum, ESyncBits actions);
bool view(struct player_struct* pp, int* vx, int* vy, int* vz, short* vsectnum, int ang, fixed_t q16horiz, double smoothratio);
void tracers(int x1, int y1, int z1, int x2, int y2, int z2, int n); void tracers(int x1, int y1, int z1, int x2, int y2, int z2, int n);
DDukeActor* aim(DDukeActor* s, int aang); DDukeActor* aim(DDukeActor* s, int aang);
void checkweapons(struct player_struct* const p); void checkweapons(struct player_struct* const p);

View file

@ -80,7 +80,6 @@ uint8_t enemysizecheat /*raat607*/, ufospawnsminion, pistonsound, chickenphase /
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// not serialized // not serialized
int cameradist = 0, cameraclock = 0; // only for 3rd person view
int otherp; // internal helper int otherp; // internal helper
int actor_tog; // cheat helper int actor_tog; // cheat helper
int playerswhenstarted; // why is this needed? int playerswhenstarted; // why is this needed?

View file

@ -46,8 +46,6 @@ struct DukeGameInfo
extern DukeGameInfo gs; extern DukeGameInfo gs;
extern int cameraclock;
extern int cameradist;
extern int otherp; // transient helper, MP only extern int otherp; // transient helper, MP only
extern int actor_tog; // cheat state extern int actor_tog; // cheat state
extern intptr_t apScriptGameEvent[]; extern intptr_t apScriptGameEvent[];

View file

@ -1064,75 +1064,4 @@ void shootbloodsplat(DDukeActor* actor, int p, int sx, int sy, int sz, int sa, i
} }
} }
//---------------------------------------------------------------------------
//
// view - as in third person view (stupid name for this function)
//
//---------------------------------------------------------------------------
bool view(struct player_struct* pp, int* vx, int* vy, int* vz, short* vsectnum, int ang, fixed_t q16horiz, double smoothratio)
{
spritetype* sp;
int i, nx, ny, nz, hx, hy, hitx, hity, hitz;
short bakcstat, hitsect, hitwall, daang;
DDukeActor* hitsprt;
nx = -bcos(ang, -4);
ny = -bsin(ang, -4);
nz = q16horiz >> 9;
sp = &pp->GetActor()->s;
bakcstat = sp->cstat;
sp->cstat &= (short)~0x101;
updatesectorz(*vx, *vy, *vz, vsectnum);
hitscan(*vx, *vy, *vz, *vsectnum, nx, ny, nz, &hitsect, &hitwall, &hitsprt, &hitx, &hity, &hitz, CLIPMASK1);
if (*vsectnum < 0)
{
sp->cstat = bakcstat;
return false;
}
hx = hitx - (*vx); hy = hity - (*vy);
if (abs(nx) + abs(ny) > abs(hx) + abs(hy))
{
*vsectnum = hitsect;
if (hitwall >= 0)
{
daang = getangle(wall[wall[hitwall].point2].x - wall[hitwall].x,
wall[wall[hitwall].point2].y - wall[hitwall].y);
i = nx * bsin(daang) + ny * -bcos(daang);
if (abs(nx) > abs(ny)) hx -= MulScale(nx, i, 28);
else hy -= MulScale(ny, i, 28);
}
else if (!hitsprt)
{
if (abs(nx) > abs(ny)) hx -= (nx >> 5);
else hy -= (ny >> 5);
}
if (abs(nx) > abs(ny)) i = DivScale(hx, nx, 16);
else i = DivScale(hy, ny, 16);
if (i < cameradist) cameradist = i;
}
*vx = (*vx) + MulScale(nx, cameradist, 16);
*vy = (*vy) + MulScale(ny, cameradist, 16);
*vz = (*vz) + MulScale(nz, cameradist, 16);
int myclock = PlayClock + int(TICSPERFRAME/65536. * smoothratio);
if (cameraclock == INT_MIN) cameraclock = myclock; // third person view was just started.
cameradist = min(cameradist + ((myclock - cameraclock) << 10), 65536);
cameraclock = myclock;
updatesectorz(*vx, *vy, *vz, vsectnum);
sp->cstat = bakcstat;
return true;
}
END_DUKE_NS END_DUKE_NS

View file

@ -587,10 +587,10 @@ void displayrooms(int snum, double smoothratio)
{ {
cposz -= isRR() ? 3840 : 3072; cposz -= isRR() ? 3840 : 3072;
if (!view(p, &cposx, &cposy, &cposz, &sect, cang.asbuild(), choriz.asq16(), smoothratio)) if (!calcChaseCamPos(&cposx, &cposy, &cposz, &p->GetActor()->s, &sect, cang, choriz, smoothratio))
{ {
cposz += isRR() ? 3840 : 3072; cposz += isRR() ? 3840 : 3072;
view(p, &cposx, &cposy, &cposz, &sect, cang.asbuild(), choriz.asq16(), smoothratio); calcChaseCamPos(&cposx, &cposy, &cposz, &p->GetActor()->s, &sect, cang, choriz, smoothratio);
} }
} }

View file

@ -38,6 +38,7 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
#include "mytypes.h" #include "mytypes.h"
#include "gamecontrol.h" #include "gamecontrol.h"
#include "gamefuncs.h"
#include "network.h" #include "network.h"
#include "pal.h" #include "pal.h"
#include "player.h" #include "player.h"
@ -925,133 +926,6 @@ post_analyzesprites(void)
} }
#endif #endif
bool
BackView(int *nx, int *ny, int *nz, short *vsect, binangle *nang, fixed_t q16horiz)
{
vec3_t n = { *nx, *ny, *nz };
SPRITEp sp;
hitdata_t hitinfo;
int i, vx, vy, vz, hx, hy;
short bakcstat, daang;
PLAYERp pp = &Player[screenpeek];
short ang;
ASSERT(*vsect >= 0 && *vsect < MAXSECTORS);
ang = nang->asbuild() + pp->view_outside_dang;
// Calculate the vector (nx,ny,nz) to shoot backwards
vx = -bcos(ang, -3);
vy = -bsin(ang, -3);
vz = q16horiz >> 8;
// Player sprite of current view
sp = &sprite[pp->PlayerSprite];
bakcstat = sp->cstat;
RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
// Make sure sector passed to FAFhitscan is correct
//COVERupdatesector(*nx, *ny, vsect);
hitscan(&n, *vsect, vx, vy, vz,
&hitinfo, CLIPMASK_PLAYER);
if (*vsect < 0)
{
sp->cstat = bakcstat;
return false;
}
ASSERT(*vsect >= 0 && *vsect < MAXSECTORS);
sp->cstat = bakcstat; // Restore cstat
hx = hitinfo.pos.x - (*nx);
hy = hitinfo.pos.y - (*ny);
// If something is in the way, make pp->camera_dist lower if necessary
if (abs(vx) + abs(vy) > abs(hx) + abs(hy))
{
if (hitinfo.wall >= 0) // Push you a little bit off the wall
{
*vsect = hitinfo.sect;
daang = getangle(wall[wall[hitinfo.wall].point2].x - wall[hitinfo.wall].x,
wall[wall[hitinfo.wall].point2].y - wall[hitinfo.wall].y);
i = vx * bsin(daang) + vy * -bcos(daang);
if (abs(vx) > abs(vy))
hx -= MulScale(vx, i, 28);
else
hy -= MulScale(vy, i, 28);
}
else if (hitinfo.sprite < 0) // Push you off the ceiling/floor
{
*vsect = hitinfo.sect;
if (abs(vx) > abs(vy))
hx -= (vx >> 5);
else
hy -= (vy >> 5);
}
else
{
SPRITEp hsp = &sprite[hitinfo.sprite];
int flag_backup;
// if you hit a sprite that's not a wall sprite - try again
if (!TEST(hsp->cstat, CSTAT_SPRITE_ALIGNMENT_WALL))
{
flag_backup = hsp->cstat;
RESET(hsp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
ASSERT(*vsect >= 0 && *vsect < MAXSECTORS);
BackView(nx, ny, nz, vsect, nang, q16horiz);
hsp->cstat = flag_backup;
return false;
}
else
{
// same as wall calculation
daang = NORM_ANGLE(sp->ang-512);
i = vx * bsin(daang) + vy * -bcos(daang);
if (abs(vx) > abs(vy))
hx -= MulScale(vx, i, 28);
else
hy -= MulScale(vy, i, 28);
}
}
if (abs(vx) > abs(vy))
i = IntToFixed(hx) / vx;
else
i = IntToFixed(hy) / vy;
if (i < pp->camera_dist)
pp->camera_dist = i;
}
// Actually move you! (Camerdist is 65536 if nothing is in the way)
*nx = (*nx) + MulScale(vx, pp->camera_dist, 16);
*ny = (*ny) + MulScale(vy, pp->camera_dist, 16);
*nz = (*nz) + MulScale(vz, pp->camera_dist, 16);
// Slowly increase pp->camera_dist until it reaches 65536
// Synctics is a timer variable so it increases the same rate
// on all speed computers
pp->camera_dist = min(pp->camera_dist + (3 << 10), 65536);
//pp->camera_dist = min(pp->camera_dist + (synctics << 10), 65536);
// Make sure vsect is correct
updatesectorz(*nx, *ny, *nz, vsect);
*nang += buildang(pp->view_outside_dang);
return true;
}
void void
CircleCamera(int *nx, int *ny, int *nz, short *vsect, binangle *nang, fixed_t q16horiz) CircleCamera(int *nx, int *ny, int *nz, short *vsect, binangle *nang, fixed_t q16horiz)
{ {
@ -1705,10 +1579,10 @@ drawscreen(PLAYERp pp, double smoothratio)
{ {
tz -= 8448; tz -= 8448;
if (!BackView(&tx, &ty, &tz, &tsectnum, &tang, thoriz.asq16())) if (!calcChaseCamPos(&tx, &ty, &tz, &sprite[pp->PlayerSprite], &tsectnum, tang, thoriz, smoothratio))
{ {
tz += 8448; tz += 8448;
BackView(&tx, &ty, &tz, &tsectnum, &tang, thoriz.asq16()); calcChaseCamPos(&tx, &ty, &tz, &sprite[pp->PlayerSprite], &tsectnum, tang, thoriz, smoothratio);
} }
} }
else else

View file

@ -839,7 +839,6 @@ struct PLAYERstruct
SPRITEp hi_sp, lo_sp; SPRITEp hi_sp, lo_sp;
SPRITEp last_camera_sp; SPRITEp last_camera_sp;
int camera_dist; // view mode dist
int circle_camera_dist; int circle_camera_dist;
int six,siy,siz; // save player interp position for PlayerSprite int six,siy,siz; // save player interp position for PlayerSprite
short siang; short siang;

View file

@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "jsector.h" #include "jsector.h"
#include "network.h" #include "network.h"
#include "gamestate.h" #include "gamestate.h"
#include "gamefuncs.h"
#include "player.h" #include "player.h"
BEGIN_SW_NS BEGIN_SW_NS
@ -99,22 +100,14 @@ void GameInterface::ToggleThirdPerson()
{ {
if (gamestate != GS_LEVEL) return; if (gamestate != GS_LEVEL) return;
auto pp = &Player[myconnectindex]; auto pp = &Player[myconnectindex];
if (inputState.ShiftPressed()) if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE))
{ {
if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE)) RESET(pp->Flags, PF_VIEW_FROM_OUTSIDE);
pp->view_outside_dang = NORM_ANGLE(pp->view_outside_dang + 256);
} }
else else
{ {
if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE)) SET(pp->Flags, PF_VIEW_FROM_OUTSIDE);
{ cameradist = 0;
RESET(pp->Flags, PF_VIEW_FROM_OUTSIDE);
}
else
{
SET(pp->Flags, PF_VIEW_FROM_OUTSIDE);
pp->camera_dist = 0;
}
} }
} }