2019-09-19 22:42:45 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
Copyright (C) 2019 Nuke.YKT
|
|
|
|
|
|
|
|
This file is part of NBlood.
|
|
|
|
|
|
|
|
NBlood is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
2019-09-21 18:59:54 +00:00
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "compat.h"
|
|
|
|
#include "build.h"
|
|
|
|
#include "pragmas.h"
|
|
|
|
#include "mmulti.h"
|
2020-07-31 19:05:09 +00:00
|
|
|
#include "v_font.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
#include "endgame.h"
|
2020-07-31 19:05:09 +00:00
|
|
|
#include "aistate.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
#include "map2d.h"
|
2020-07-31 19:05:09 +00:00
|
|
|
#include "loadsave.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
#include "sectorfx.h"
|
2020-07-31 19:05:09 +00:00
|
|
|
#include "choke.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
#include "view.h"
|
2020-02-07 19:47:43 +00:00
|
|
|
#include "nnexts.h"
|
2019-11-10 10:42:25 +00:00
|
|
|
#include "zstring.h"
|
2020-06-14 16:57:55 +00:00
|
|
|
#include "menu.h"
|
2019-12-09 01:01:30 +00:00
|
|
|
#include "gstrings.h"
|
2019-12-30 18:29:32 +00:00
|
|
|
#include "v_2ddrawer.h"
|
2020-01-12 19:28:07 +00:00
|
|
|
#include "v_video.h"
|
2020-07-31 19:05:09 +00:00
|
|
|
#include "v_font.h"
|
2020-05-30 22:01:00 +00:00
|
|
|
#include "glbackend/glbackend.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-09-22 06:39:22 +00:00
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
VIEW gPrevView[kMaxPlayers];
|
|
|
|
VIEWPOS gViewPos;
|
|
|
|
int gViewIndex;
|
|
|
|
|
|
|
|
struct INTERPOLATE {
|
|
|
|
void *pointer;
|
|
|
|
int value;
|
|
|
|
int value2;
|
|
|
|
INTERPOLATE_TYPE type;
|
|
|
|
};
|
|
|
|
|
|
|
|
int gViewMode = 3;
|
|
|
|
int gViewSize = 2;
|
|
|
|
|
|
|
|
int gInterpolate;
|
|
|
|
int nInterpolations;
|
2019-07-24 13:58:45 +00:00
|
|
|
char gInterpolateSprite[(kMaxSprites+7)>>3];
|
|
|
|
char gInterpolateWall[(kMaxWalls+7)>>3];
|
|
|
|
char gInterpolateSector[(kMaxSectors+7)>>3];
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-07-24 13:58:45 +00:00
|
|
|
#define kMaxInterpolations 16384
|
|
|
|
|
|
|
|
INTERPOLATE gInterpolation[kMaxInterpolations];
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
int gViewXCenter, gViewYCenter;
|
|
|
|
int gViewX0, gViewY0, gViewX1, gViewY1;
|
|
|
|
int gViewX0S, gViewY0S, gViewX1S, gViewY1S;
|
2020-08-02 06:39:51 +00:00
|
|
|
int xscale, yscale, xstep, ystep;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
int gScreenTilt;
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-07-31 19:05:09 +00:00
|
|
|
FFont *gFont[kFontNum];
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
void FontSet(int id, int tile, int space)
|
|
|
|
{
|
2020-01-02 09:45:31 +00:00
|
|
|
if (id < 0 || id >= kFontNum || tile < 0 || tile >= kMaxTiles)
|
2019-09-19 22:42:45 +00:00
|
|
|
return;
|
|
|
|
|
2020-07-31 19:05:09 +00:00
|
|
|
GlyphSet glyphs;
|
|
|
|
for (int i = 1; i < 96; i++)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-07-31 19:05:09 +00:00
|
|
|
auto tex = tileGetTexture(tile + i);
|
2020-07-31 19:05:57 +00:00
|
|
|
if (tex && tex->isValid() && tex->GetTexelWidth() > 0 && tex->GetTexelHeight() > 0)
|
|
|
|
{
|
2020-07-31 19:05:09 +00:00
|
|
|
glyphs.Insert(i + 32, tex);
|
2020-07-31 19:05:57 +00:00
|
|
|
tex->SetOffsetsNotForFont();
|
|
|
|
}
|
2020-07-31 19:05:09 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-07-31 19:05:09 +00:00
|
|
|
const char *names[] = { "smallfont", "bigfont", "gothfont", "smallfont2", "digifont"};
|
|
|
|
const char *defs[] = { "defsmallfont", "defbigfont", nullptr, "defsmallfont2", nullptr};
|
|
|
|
FFont ** ptrs[] = { &SmallFont, &BigFont, nullptr, &SmallFont2, nullptr};
|
2020-07-31 19:05:57 +00:00
|
|
|
gFont[id] = new ::FFont(names[id], nullptr, defs[id], 0, 0, 0, 0, tileWidth(tile), false, false, false, &glyphs);
|
|
|
|
gFont[id]->SetKerning(space);
|
2020-07-31 19:05:09 +00:00
|
|
|
if (ptrs[id]) *ptrs[id] = gFont[id];
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void viewToggle(int viewMode)
|
|
|
|
{
|
|
|
|
if (viewMode == 3)
|
|
|
|
gViewMode = 4;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gViewMode = 3;
|
|
|
|
viewResizeView(gViewSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void viewBackupView(int nPlayer)
|
|
|
|
{
|
|
|
|
PLAYER *pPlayer = &gPlayer[nPlayer];
|
|
|
|
VIEW *pView = &gPrevView[nPlayer];
|
|
|
|
pView->at30 = pPlayer->q16ang;
|
|
|
|
pView->at50 = pPlayer->pSprite->x;
|
|
|
|
pView->at54 = pPlayer->pSprite->y;
|
2019-10-21 19:46:41 +00:00
|
|
|
pView->at38 = pPlayer->zView;
|
|
|
|
pView->at34 = pPlayer->zWeapon-pPlayer->zView-0xc00;
|
2019-09-19 22:42:45 +00:00
|
|
|
pView->at24 = pPlayer->q16horiz;
|
|
|
|
pView->at28 = pPlayer->q16slopehoriz;
|
2019-10-21 19:46:41 +00:00
|
|
|
pView->at2c = pPlayer->slope;
|
|
|
|
pView->at8 = pPlayer->bobHeight;
|
|
|
|
pView->atc = pPlayer->bobWidth;
|
|
|
|
pView->at18 = pPlayer->swayHeight;
|
|
|
|
pView->at1c = pPlayer->swayWidth;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
2019-09-07 16:39:26 +00:00
|
|
|
void viewCorrectViewOffsets(int nPlayer, vec3_t const *oldpos)
|
|
|
|
{
|
|
|
|
PLAYER *pPlayer = &gPlayer[nPlayer];
|
|
|
|
VIEW *pView = &gPrevView[nPlayer];
|
|
|
|
pView->at50 += pPlayer->pSprite->x-oldpos->x;
|
|
|
|
pView->at54 += pPlayer->pSprite->y-oldpos->y;
|
|
|
|
pView->at38 += pPlayer->pSprite->z-oldpos->z;
|
|
|
|
}
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
void viewClearInterpolations(void)
|
|
|
|
{
|
|
|
|
nInterpolations = 0;
|
|
|
|
memset(gInterpolateSprite, 0, sizeof(gInterpolateSprite));
|
|
|
|
memset(gInterpolateWall, 0, sizeof(gInterpolateWall));
|
|
|
|
memset(gInterpolateSector, 0, sizeof(gInterpolateSector));
|
|
|
|
}
|
|
|
|
|
|
|
|
void viewAddInterpolation(void *data, INTERPOLATE_TYPE type)
|
|
|
|
{
|
2019-07-24 13:58:45 +00:00
|
|
|
if (nInterpolations == kMaxInterpolations)
|
2019-09-19 22:42:45 +00:00
|
|
|
ThrowError("Too many interpolations");
|
|
|
|
INTERPOLATE *pInterpolate = &gInterpolation[nInterpolations++];
|
|
|
|
pInterpolate->pointer = data;
|
|
|
|
pInterpolate->type = type;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case INTERPOLATE_TYPE_INT:
|
|
|
|
pInterpolate->value = *((int*)data);
|
|
|
|
break;
|
|
|
|
case INTERPOLATE_TYPE_SHORT:
|
|
|
|
pInterpolate->value = *((short*)data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalcInterpolations(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
INTERPOLATE *pInterpolate = gInterpolation;
|
|
|
|
for (i = 0; i < nInterpolations; i++, pInterpolate++)
|
|
|
|
{
|
|
|
|
switch (pInterpolate->type)
|
|
|
|
{
|
|
|
|
case INTERPOLATE_TYPE_INT:
|
|
|
|
{
|
|
|
|
pInterpolate->value2 = *((int*)pInterpolate->pointer);
|
|
|
|
int newValue = interpolate(pInterpolate->value, *((int*)pInterpolate->pointer), gInterpolate);
|
|
|
|
*((int*)pInterpolate->pointer) = newValue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case INTERPOLATE_TYPE_SHORT:
|
|
|
|
{
|
|
|
|
pInterpolate->value2 = *((short*)pInterpolate->pointer);
|
|
|
|
int newValue = interpolate(pInterpolate->value, *((short*)pInterpolate->pointer), gInterpolate);
|
|
|
|
*((short*)pInterpolate->pointer) = newValue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RestoreInterpolations(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
INTERPOLATE *pInterpolate = gInterpolation;
|
|
|
|
for (i = 0; i < nInterpolations; i++, pInterpolate++)
|
|
|
|
{
|
|
|
|
switch (pInterpolate->type)
|
|
|
|
{
|
|
|
|
case INTERPOLATE_TYPE_INT:
|
|
|
|
*((int*)pInterpolate->pointer) = pInterpolate->value2;
|
|
|
|
break;
|
|
|
|
case INTERPOLATE_TYPE_SHORT:
|
|
|
|
*((short*)pInterpolate->pointer) = pInterpolate->value2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void viewDrawText(int nFont, const char *pString, int x, int y, int nShade, int nPalette, int position, char shadow, unsigned int nStat, uint8_t alpha)
|
|
|
|
{
|
2020-01-02 09:45:31 +00:00
|
|
|
if (nFont < 0 || nFont >= kFontNum || !pString) return;
|
2020-07-31 19:05:09 +00:00
|
|
|
FFont *pFont = gFont[nFont];
|
2020-07-14 13:25:35 +00:00
|
|
|
|
|
|
|
//y += pFont->yoff;
|
|
|
|
|
2020-07-31 19:05:09 +00:00
|
|
|
if (position) x -= pFont->StringWidth(pString) / 2;
|
|
|
|
|
|
|
|
if (shadow)
|
|
|
|
{
|
2020-08-01 18:07:32 +00:00
|
|
|
DrawText(twod, pFont, CR_UNDEFINED, x+1, y+1, pString, DTA_FullscreenScale, 3, DTA_VirtualWidth, 320, DTA_VirtualHeight, 200, DTA_Color, 0xff000000, DTA_Alpha, 0.5, TAG_DONE);
|
2020-07-31 19:05:09 +00:00
|
|
|
}
|
|
|
|
DrawText(twod, pFont, CR_UNDEFINED, x, y, pString, DTA_FullscreenScale, 3, DTA_VirtualWidth, 320, DTA_VirtualHeight, 200, DTA_TranslationIndex, TRANSLATION(Translation_Remap, nPalette),
|
2020-08-02 17:43:45 +00:00
|
|
|
DTA_Color, shadeToLight(nShade), DTA_Alpha, alpha / 255., TAG_DONE);
|
2020-08-01 18:07:32 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InitStatusBar(void)
|
|
|
|
{
|
|
|
|
tileLoadTile(2200);
|
|
|
|
}
|
2019-12-08 23:55:30 +00:00
|
|
|
GameStats GameInterface::getStats()
|
|
|
|
{
|
2020-04-01 20:34:49 +00:00
|
|
|
return { gKillMgr.at4, gKillMgr.at0, gSecretMgr.at4, gSecretMgr.at0, gLevelTime / kTicsPerSec, gPlayer[myconnectindex].fragCount };
|
2019-12-08 23:55:30 +00:00
|
|
|
}
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
void viewDrawMapTitle(void)
|
|
|
|
{
|
2019-12-01 09:18:38 +00:00
|
|
|
if (!hud_showmapname || M_Active())
|
2019-09-19 22:42:45 +00:00
|
|
|
return;
|
|
|
|
|
2020-08-02 17:43:45 +00:00
|
|
|
int const fadeStartTic = kTicsPerSec;
|
2019-09-14 06:47:20 +00:00
|
|
|
int const fadeEndTic = int(1.5f*kTicsPerSec);
|
2019-09-13 10:15:16 +00:00
|
|
|
if (gLevelTime > fadeEndTic)
|
2019-09-19 22:42:45 +00:00
|
|
|
return;
|
2020-08-02 17:43:45 +00:00
|
|
|
int const alpha = 255 - clamp((gLevelTime-fadeStartTic)*255/(fadeEndTic-fadeStartTic), 0, 255);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-08-02 17:43:45 +00:00
|
|
|
if (alpha != 0)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
viewDrawText(1, levelGetTitle(), 160, 50, -128, 0, 1, 1, 0, alpha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-27 16:55:14 +00:00
|
|
|
void viewDrawAimedPlayerName(void)
|
|
|
|
{
|
|
|
|
if (!cl_idplayers || (gView->aim.dx == 0 && gView->aim.dy == 0))
|
|
|
|
return;
|
|
|
|
|
|
|
|
int hit = HitScan(gView->pSprite, gView->pSprite->z, gView->aim.dx, gView->aim.dy, gView->aim.dz, CLIPMASK0, 512);
|
|
|
|
if (hit == 3)
|
|
|
|
{
|
|
|
|
spritetype* pSprite = &sprite[gHitInfo.hitsprite];
|
|
|
|
if (IsPlayerSprite(pSprite))
|
|
|
|
{
|
|
|
|
char nPlayer = pSprite->type-kDudePlayer1;
|
|
|
|
char* szName = gProfile[nPlayer].name;
|
|
|
|
int nPalette = (gPlayer[nPlayer].teamId&3)+11;
|
|
|
|
viewDrawText(4, szName, 160, 125, -128, nPalette, 1, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-02 11:01:18 +00:00
|
|
|
void viewPrecacheTiles(void)
|
|
|
|
{
|
|
|
|
tilePrecacheTile(2173, 0);
|
|
|
|
tilePrecacheTile(2200, 0);
|
|
|
|
tilePrecacheTile(2201, 0);
|
|
|
|
tilePrecacheTile(2202, 0);
|
|
|
|
tilePrecacheTile(2207, 0);
|
|
|
|
tilePrecacheTile(2208, 0);
|
|
|
|
tilePrecacheTile(2209, 0);
|
|
|
|
tilePrecacheTile(2229, 0);
|
|
|
|
tilePrecacheTile(2260, 0);
|
|
|
|
tilePrecacheTile(2559, 0);
|
|
|
|
tilePrecacheTile(2169, 0);
|
|
|
|
tilePrecacheTile(2578, 0);
|
|
|
|
tilePrecacheTile(2586, 0);
|
|
|
|
tilePrecacheTile(2602, 0);
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
tilePrecacheTile(2190 + i, 0);
|
|
|
|
tilePrecacheTile(2230 + i, 0);
|
|
|
|
tilePrecacheTile(2240 + i, 0);
|
|
|
|
tilePrecacheTile(2250 + i, 0);
|
|
|
|
tilePrecacheTile(kSBarNumberHealth + i, 0);
|
|
|
|
tilePrecacheTile(kSBarNumberAmmo + i, 0);
|
|
|
|
tilePrecacheTile(kSBarNumberInv + i, 0);
|
|
|
|
tilePrecacheTile(kSBarNumberArmor1 + i, 0);
|
|
|
|
tilePrecacheTile(kSBarNumberArmor2 + i, 0);
|
|
|
|
tilePrecacheTile(kSBarNumberArmor3 + i, 0);
|
|
|
|
}
|
2020-08-01 19:23:33 +00:00
|
|
|
/*
|
2020-01-02 11:01:18 +00:00
|
|
|
for (int i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
tilePrecacheTile(gPackIcons[i], 0);
|
|
|
|
tilePrecacheTile(gPackIcons2[i].nTile, 0);
|
|
|
|
}
|
2020-08-01 19:23:33 +00:00
|
|
|
*/
|
2020-01-02 11:01:18 +00:00
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
tilePrecacheTile(2220 + i, 0);
|
|
|
|
tilePrecacheTile(2552 + i, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-11 21:54:33 +00:00
|
|
|
static TArray<uint8_t> lensdata;
|
2019-09-19 22:42:45 +00:00
|
|
|
int *lensTable;
|
|
|
|
|
|
|
|
int gZoom = 1024;
|
|
|
|
|
2020-08-02 17:59:14 +00:00
|
|
|
extern int dword_172CE0[16][3];
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
void viewInit(void)
|
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("Initializing status bar\n");
|
2019-09-19 22:42:45 +00:00
|
|
|
InitStatusBar();
|
|
|
|
FontSet(0, 4096, 0);
|
|
|
|
FontSet(1, 4192, 1);
|
|
|
|
FontSet(2, 4288, 1);
|
|
|
|
FontSet(3, 4384, 1);
|
|
|
|
FontSet(4, 4480, 0);
|
2020-08-02 11:35:34 +00:00
|
|
|
enginePostInit(); // This must not be done earlier!
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-04-11 21:54:33 +00:00
|
|
|
lensdata = fileSystem.LoadFile("lens.dat");
|
|
|
|
dassert(lensdata.Size() == kLensSize * kLensSize * sizeof(int));
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-04-11 21:54:33 +00:00
|
|
|
lensTable = (int*)lensdata.Data();
|
2019-09-19 22:42:45 +00:00
|
|
|
#if B_BIG_ENDIAN == 1
|
|
|
|
for (int i = 0; i < kLensSize*kLensSize; i++)
|
|
|
|
{
|
|
|
|
lensTable[i] = B_LITTLE32(lensTable[i]);
|
|
|
|
}
|
|
|
|
#endif
|
2020-05-24 10:31:38 +00:00
|
|
|
uint8_t *data = tileAllocTile(4077, kLensSize, kLensSize);
|
2020-04-11 22:04:02 +00:00
|
|
|
memset(data, TRANSPARENT_INDEX, kLensSize*kLensSize);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
dword_172CE0[i][0] = mulscale16(wrand(), 2048);
|
|
|
|
dword_172CE0[i][1] = mulscale16(wrand(), 2048);
|
|
|
|
dword_172CE0[i][2] = mulscale16(wrand(), 2048);
|
|
|
|
}
|
|
|
|
gViewMap.sub_25C38(0, 0, gZoom, 0, gFollowMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
void viewResizeView(int size)
|
|
|
|
{
|
|
|
|
int xdimcorrect = ClipHigh(scale(ydim, 4, 3), xdim);
|
|
|
|
gViewXCenter = xdim-xdim/2;
|
|
|
|
gViewYCenter = ydim-ydim/2;
|
|
|
|
xscale = divscale16(xdim, 320);
|
2020-08-02 06:39:51 +00:00
|
|
|
int xscalecorrect = divscale16(xdimcorrect, 320);
|
2019-09-19 22:42:45 +00:00
|
|
|
yscale = divscale16(ydim, 200);
|
|
|
|
xstep = divscale16(320, xdim);
|
|
|
|
ystep = divscale16(200, ydim);
|
|
|
|
gViewSize = ClipRange(size, 0, 7);
|
|
|
|
if (gViewSize <= 2)
|
|
|
|
{
|
|
|
|
gViewX0 = 0;
|
|
|
|
gViewX1 = xdim-1;
|
|
|
|
gViewY0 = 0;
|
|
|
|
gViewY1 = ydim-1;
|
2019-09-18 09:13:04 +00:00
|
|
|
if (gGameOptions.nGameType > 0 && gGameOptions.nGameType <= 3)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
gViewY0 = (tilesiz[2229].y*ydim*((gNetPlayers+3)/4))/200;
|
|
|
|
}
|
|
|
|
gViewX0S = divscale16(gViewX0, xscalecorrect);
|
|
|
|
gViewY0S = divscale16(gViewY0, yscale);
|
|
|
|
gViewX1S = divscale16(gViewX1, xscalecorrect);
|
|
|
|
gViewY1S = divscale16(gViewY1, yscale);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gViewX0 = 0;
|
|
|
|
gViewY0 = 0;
|
|
|
|
gViewX1 = xdim-1;
|
2020-08-02 06:48:23 +00:00
|
|
|
int gy1 = (25 * ydim) / 200;
|
|
|
|
if (gViewSize == 3) // full status bar must scale the bottom to the actual display height.
|
|
|
|
gy1 = Scale(gy1, hud_scale, 100);
|
|
|
|
gViewY1 = ydim-1- gy1;
|
2019-09-18 09:13:04 +00:00
|
|
|
if (gGameOptions.nGameType > 0 && gGameOptions.nGameType <= 3)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
gViewY0 = (tilesiz[2229].y*ydim*((gNetPlayers+3)/4))/200;
|
|
|
|
}
|
|
|
|
|
|
|
|
int height = gViewY1-gViewY0;
|
|
|
|
gViewX0 += mulscale16(xdim*(gViewSize-3),4096);
|
|
|
|
gViewX1 -= mulscale16(xdim*(gViewSize-3),4096);
|
|
|
|
gViewY0 += mulscale16(height*(gViewSize-3),4096);
|
|
|
|
gViewY1 -= mulscale16(height*(gViewSize-3),4096);
|
|
|
|
gViewX0S = divscale16(gViewX0, xscalecorrect);
|
|
|
|
gViewY0S = divscale16(gViewY0, yscale);
|
|
|
|
gViewX1S = divscale16(gViewX1, xscalecorrect);
|
|
|
|
gViewY1S = divscale16(gViewY1, yscale);
|
|
|
|
}
|
|
|
|
videoSetViewableArea(gViewX0, gViewY0, gViewX1, gViewY1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-07 13:15:39 +00:00
|
|
|
void viewDrawInterface(ClockTicks arg)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
UpdateStatusBar(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
int othercameradist = 1280;
|
|
|
|
int cameradist = -1;
|
2019-09-07 16:39:26 +00:00
|
|
|
int othercameraclock, cameraclock;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
void CalcOtherPosition(spritetype *pSprite, int *pX, int *pY, int *pZ, int *vsectnum, int nAng, fix16_t zm)
|
|
|
|
{
|
|
|
|
int vX = mulscale30(-Cos(nAng), 1280);
|
|
|
|
int vY = mulscale30(-Sin(nAng), 1280);
|
|
|
|
int vZ = fix16_to_int(mulscale(zm, 1280, 3))-(16<<8);
|
|
|
|
int bakCstat = pSprite->cstat;
|
|
|
|
pSprite->cstat &= ~256;
|
|
|
|
dassert(*vsectnum >= 0 && *vsectnum < kMaxSectors);
|
|
|
|
FindSector(*pX, *pY, *pZ, vsectnum);
|
|
|
|
short nHSector;
|
|
|
|
int hX, hY;
|
|
|
|
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 (klabs(vX)+klabs(vY) > klabs(dX)+klabs(dY))
|
|
|
|
{
|
|
|
|
*vsectnum = nHSector;
|
|
|
|
dX -= ksgn(vX)<<6;
|
|
|
|
dY -= ksgn(vY)<<6;
|
|
|
|
int nDist;
|
|
|
|
if (klabs(vX) > klabs(vY))
|
|
|
|
{
|
|
|
|
nDist = ClipHigh(divscale16(dX,vX), othercameradist);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nDist = ClipHigh(divscale16(dY,vY), othercameradist);
|
|
|
|
}
|
|
|
|
othercameradist = nDist;
|
|
|
|
}
|
|
|
|
*pX += mulscale16(vX, othercameradist);
|
|
|
|
*pY += mulscale16(vY, othercameradist);
|
|
|
|
*pZ += mulscale16(vZ, othercameradist);
|
2019-09-07 13:15:39 +00:00
|
|
|
othercameradist = ClipHigh(othercameradist+(((int)(totalclock-othercameraclock))<<10), 65536);
|
2019-09-07 16:39:26 +00:00
|
|
|
othercameraclock = (int)totalclock;
|
2019-09-19 22:42:45 +00:00
|
|
|
dassert(*vsectnum >= 0 && *vsectnum < kMaxSectors);
|
|
|
|
FindSector(*pX, *pY, *pZ, vsectnum);
|
|
|
|
pSprite->cstat = bakCstat;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalcPosition(spritetype *pSprite, int *pX, int *pY, int *pZ, int *vsectnum, int nAng, fix16_t zm)
|
|
|
|
{
|
|
|
|
int vX = mulscale30(-Cos(nAng), 1280);
|
|
|
|
int vY = mulscale30(-Sin(nAng), 1280);
|
|
|
|
int vZ = fix16_to_int(mulscale(zm, 1280, 3))-(16<<8);
|
|
|
|
int bakCstat = pSprite->cstat;
|
|
|
|
pSprite->cstat &= ~256;
|
|
|
|
dassert(*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 (klabs(vX)+klabs(vY) > klabs(dX)+klabs(dY))
|
|
|
|
{
|
|
|
|
*vsectnum = nHSector;
|
|
|
|
dX -= ksgn(vX)<<6;
|
|
|
|
dY -= ksgn(vY)<<6;
|
|
|
|
int nDist;
|
|
|
|
if (klabs(vX) > klabs(vY))
|
|
|
|
{
|
|
|
|
nDist = ClipHigh(divscale16(dX,vX), cameradist);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nDist = ClipHigh(divscale16(dY,vY), cameradist);
|
|
|
|
}
|
|
|
|
cameradist = nDist;
|
|
|
|
}
|
|
|
|
*pX += mulscale16(vX, cameradist);
|
|
|
|
*pY += mulscale16(vY, cameradist);
|
|
|
|
*pZ += mulscale16(vZ, cameradist);
|
2019-09-07 13:15:39 +00:00
|
|
|
cameradist = ClipHigh(cameradist+(((int)(totalclock-cameraclock))<<10), 65536);
|
2019-09-07 16:39:26 +00:00
|
|
|
cameraclock = (int)totalclock;
|
2019-09-19 22:42:45 +00:00
|
|
|
dassert(*vsectnum >= 0 && *vsectnum < kMaxSectors);
|
|
|
|
FindSector(*pX, *pY, *pZ, vsectnum);
|
|
|
|
pSprite->cstat = bakCstat;
|
|
|
|
}
|
|
|
|
|
2019-10-07 19:29:52 +00:00
|
|
|
// by NoOne: show warning msgs in game instead of throwing errors (in some cases)
|
|
|
|
void viewSetSystemMessage(const char* pMessage, ...) {
|
2019-10-19 19:11:39 +00:00
|
|
|
char buffer[1024]; va_list args; va_start(args, pMessage);
|
2019-10-07 19:29:52 +00:00
|
|
|
vsprintf(buffer, pMessage, args);
|
2019-10-19 19:11:39 +00:00
|
|
|
|
2019-12-04 20:35:35 +00:00
|
|
|
Printf(PRINT_HIGH | PRINT_NOTIFY, "%s\n", buffer); // print it also in console
|
2019-10-07 19:29:52 +00:00
|
|
|
}
|
|
|
|
|
2019-09-19 06:10:18 +00:00
|
|
|
void viewSetMessage(const char *pMessage, const int pal, const MESSAGE_PRIORITY priority)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-04 20:35:35 +00:00
|
|
|
int printlevel = priority < 0 ? PRINT_LOW : priority < MESSAGE_PRIORITY_SYSTEM ? PRINT_MEDIUM : PRINT_HIGH;
|
|
|
|
Printf(printlevel|PRINT_NOTIFY, "%s\n", pMessage);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char errMsg[256];
|
|
|
|
|
|
|
|
void viewSetErrorMessage(const char *pMessage)
|
|
|
|
{
|
|
|
|
if (!pMessage)
|
|
|
|
{
|
|
|
|
strcpy(errMsg, "");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(errMsg, pMessage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DoLensEffect(void)
|
|
|
|
{
|
2019-10-11 21:31:59 +00:00
|
|
|
// To investigate whether this can be implemented as a shader effect.
|
|
|
|
auto d = tileData(4077);
|
2019-09-19 22:42:45 +00:00
|
|
|
dassert(d != NULL);
|
2019-10-11 21:31:59 +00:00
|
|
|
auto s = tilePtr(4079);
|
2019-09-19 22:42:45 +00:00
|
|
|
dassert(s != NULL);
|
|
|
|
for (int i = 0; i < kLensSize*kLensSize; i++, d++)
|
|
|
|
if (lensTable[i] >= 0)
|
|
|
|
*d = s[lensTable[i]];
|
|
|
|
tileInvalidate(4077, -1, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateDacs(int nPalette, bool bNoTint)
|
|
|
|
{
|
2020-07-27 21:29:10 +00:00
|
|
|
gLastPal = 0;
|
|
|
|
auto& tint = lookups.tables[MAXPALOOKUPS - 1];
|
|
|
|
tint.tintFlags = 0;
|
|
|
|
switch (nPalette)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-07-27 21:29:10 +00:00
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
tint.tintColor.r = 255;
|
|
|
|
tint.tintColor.g = 255;
|
|
|
|
tint.tintColor.b = 255;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
tint.tintColor.r = 132;
|
|
|
|
tint.tintColor.g = 164;
|
|
|
|
tint.tintColor.b = 255;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
tint.tintColor.r = 255;
|
|
|
|
tint.tintColor.g = 126;
|
|
|
|
tint.tintColor.b = 105;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
tint.tintColor.r = 162;
|
|
|
|
tint.tintColor.g = 186;
|
|
|
|
tint.tintColor.b = 15;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
tint.tintColor.r = 255;
|
|
|
|
tint.tintColor.g = 255;
|
|
|
|
tint.tintColor.b = 255;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
videoSetPalette(nPalette);
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-07-27 21:29:10 +00:00
|
|
|
void UpdateBlend()
|
|
|
|
{
|
|
|
|
int nRed = 0;
|
|
|
|
int nGreen = 0;
|
|
|
|
int nBlue = 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-07-27 21:29:10 +00:00
|
|
|
nRed += gView->pickupEffect;
|
|
|
|
nGreen += gView->pickupEffect;
|
|
|
|
nBlue -= gView->pickupEffect;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-07-27 21:29:10 +00:00
|
|
|
nRed += ClipHigh(gView->painEffect, 85) * 2;
|
|
|
|
nGreen -= ClipHigh(gView->painEffect, 85) * 3;
|
|
|
|
nBlue -= ClipHigh(gView->painEffect, 85) * 3;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-07-27 21:29:10 +00:00
|
|
|
nRed -= gView->blindEffect;
|
|
|
|
nGreen -= gView->blindEffect;
|
|
|
|
nBlue -= gView->blindEffect;
|
|
|
|
|
|
|
|
nRed -= gView->chokeEffect >> 6;
|
|
|
|
nGreen -= gView->chokeEffect >> 5;
|
|
|
|
nBlue -= gView->chokeEffect >> 6;
|
|
|
|
|
|
|
|
nRed = ClipRange(nRed, -255, 255);
|
|
|
|
nGreen = ClipRange(nGreen, -255, 255);
|
|
|
|
nBlue = ClipRange(nBlue, -255, 255);
|
|
|
|
|
|
|
|
videoTintBlood(nRed, nGreen, nBlue);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char otherMirrorGotpic[2];
|
|
|
|
char bakMirrorGotpic[2];
|
|
|
|
// int gVisibility;
|
|
|
|
|
|
|
|
int deliriumTilt, deliriumTurn, deliriumPitch;
|
|
|
|
int gScreenTiltO, deliriumTurnO, deliriumPitchO;
|
|
|
|
|
|
|
|
int gShowFrameRate = 1;
|
|
|
|
|
|
|
|
void viewUpdateDelirium(void)
|
|
|
|
{
|
|
|
|
gScreenTiltO = gScreenTilt;
|
|
|
|
deliriumTurnO = deliriumTurn;
|
|
|
|
deliriumPitchO = deliriumPitch;
|
|
|
|
int powerCount;
|
2019-10-19 19:11:39 +00:00
|
|
|
if ((powerCount = powerupCheck(gView, kPwUpDeliriumShroom)) != 0)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
int tilt1 = 170, tilt2 = 170, pitch = 20;
|
2019-09-07 13:15:39 +00:00
|
|
|
int timer = (int)gFrameClock*4;
|
2019-09-19 22:42:45 +00:00
|
|
|
if (powerCount < 512)
|
|
|
|
{
|
|
|
|
int powerScale = (powerCount<<16) / 512;
|
|
|
|
tilt1 = mulscale16(tilt1, powerScale);
|
|
|
|
tilt2 = mulscale16(tilt2, powerScale);
|
|
|
|
pitch = mulscale16(pitch, powerScale);
|
|
|
|
}
|
|
|
|
int sin2 = costable[(2*timer-512)&2047] / 2;
|
|
|
|
int sin3 = costable[(3*timer-512)&2047] / 2;
|
|
|
|
gScreenTilt = mulscale30(sin2+sin3,tilt1);
|
|
|
|
int sin4 = costable[(4*timer-512)&2047] / 2;
|
|
|
|
deliriumTurn = mulscale30(sin3+sin4,tilt2);
|
|
|
|
int sin5 = costable[(5*timer-512)&2047] / 2;
|
|
|
|
deliriumPitch = mulscale30(sin4+sin5,pitch);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gScreenTilt = ((gScreenTilt+1024)&2047)-1024;
|
|
|
|
if (gScreenTilt > 0)
|
|
|
|
{
|
|
|
|
gScreenTilt -= 8;
|
|
|
|
if (gScreenTilt < 0)
|
|
|
|
gScreenTilt = 0;
|
|
|
|
}
|
|
|
|
else if (gScreenTilt < 0)
|
|
|
|
{
|
|
|
|
gScreenTilt += 8;
|
|
|
|
if (gScreenTilt >= 0)
|
|
|
|
gScreenTilt = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int shakeHoriz, shakeAngle, shakeX, shakeY, shakeZ, shakeBobX, shakeBobY;
|
|
|
|
|
|
|
|
void viewUpdateShake(void)
|
|
|
|
{
|
|
|
|
shakeHoriz = 0;
|
|
|
|
shakeAngle = 0;
|
|
|
|
shakeX = 0;
|
|
|
|
shakeY = 0;
|
|
|
|
shakeZ = 0;
|
|
|
|
shakeBobX = 0;
|
|
|
|
shakeBobY = 0;
|
2019-10-21 19:46:41 +00:00
|
|
|
if (gView->flickerEffect)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-10-21 19:46:41 +00:00
|
|
|
int nValue = ClipHigh(gView->flickerEffect * 8, 2000);
|
2019-09-19 22:42:45 +00:00
|
|
|
shakeHoriz += QRandom2(nValue >> 8);
|
|
|
|
shakeAngle += QRandom2(nValue >> 8);
|
|
|
|
shakeX += QRandom2(nValue >> 4);
|
|
|
|
shakeY += QRandom2(nValue >> 4);
|
|
|
|
shakeZ += QRandom2(nValue);
|
|
|
|
shakeBobX += QRandom2(nValue);
|
|
|
|
shakeBobY += QRandom2(nValue);
|
|
|
|
}
|
2019-10-21 19:46:41 +00:00
|
|
|
if (gView->quakeEffect)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-10-21 19:46:41 +00:00
|
|
|
int nValue = ClipHigh(gView->quakeEffect * 8, 2000);
|
2019-09-19 22:42:45 +00:00
|
|
|
shakeHoriz += QRandom2(nValue >> 8);
|
|
|
|
shakeAngle += QRandom2(nValue >> 8);
|
|
|
|
shakeX += QRandom2(nValue >> 4);
|
|
|
|
shakeY += QRandom2(nValue >> 4);
|
|
|
|
shakeZ += QRandom2(nValue);
|
|
|
|
shakeBobX += QRandom2(nValue);
|
|
|
|
shakeBobY += QRandom2(nValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int gLastPal = 0;
|
|
|
|
|
|
|
|
int32_t g_frameRate;
|
|
|
|
|
2020-01-14 20:20:46 +00:00
|
|
|
void viewDrawScreen(bool sceneonly)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
int nPalette = 0;
|
2019-09-07 13:15:39 +00:00
|
|
|
static ClockTicks lastUpdate;
|
2019-10-22 22:30:51 +00:00
|
|
|
int defaultHoriz = r_horizcenter ? 100 : 90;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
#ifdef USE_OPENGL
|
|
|
|
polymostcenterhoriz = defaultHoriz;
|
|
|
|
#endif
|
2019-09-07 13:15:39 +00:00
|
|
|
ClockTicks delta = totalclock - lastUpdate;
|
|
|
|
if (delta < 0)
|
|
|
|
delta = 0;
|
|
|
|
lastUpdate = totalclock;
|
2020-05-29 01:20:40 +00:00
|
|
|
if (!paused && (!M_Active() || gGameOptions.nGameType != 0))
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-07-14 10:48:56 +00:00
|
|
|
gInterpolate = CalcSmoothRatio(totalclock, gNetFifoClock - 4, 30);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-07-14 10:48:56 +00:00
|
|
|
else gInterpolate = 65536;
|
|
|
|
|
2019-10-22 00:15:24 +00:00
|
|
|
if (cl_interpolate)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
CalcInterpolations();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gViewMode == 3 || gViewMode == 4 || gOverlayMap)
|
|
|
|
{
|
2020-02-05 21:37:20 +00:00
|
|
|
DoSectorLighting();
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
if (gViewMode == 3 || gOverlayMap)
|
|
|
|
{
|
2020-07-27 21:29:10 +00:00
|
|
|
int basepal = 0;
|
|
|
|
if (powerupCheck(gView, kPwUpDeathMask) > 0) basepal = 4;
|
|
|
|
else if (powerupCheck(gView, kPwUpReflectShots) > 0) basepal = 1;
|
|
|
|
else if (gView->isUnderwater) {
|
|
|
|
if (gView->nWaterPal) basepal = gView->nWaterPal;
|
|
|
|
else {
|
|
|
|
if (gView->pXSprite->medium == kMediumWater) basepal = 1;
|
|
|
|
else if (gView->pXSprite->medium == kMediumGoo) basepal = 3;
|
|
|
|
else basepal = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
UpdateDacs(basepal);
|
|
|
|
UpdateBlend();
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
int yxAspect = yxaspect;
|
|
|
|
int viewingRange = viewingrange;
|
|
|
|
if (r_usenewaspect)
|
|
|
|
{
|
|
|
|
newaspect_enable = 1;
|
|
|
|
videoSetCorrectedAspect();
|
|
|
|
}
|
2020-01-25 10:56:13 +00:00
|
|
|
|
|
|
|
int v1 = Blrintf(double(viewingrange) * tan(r_fov * (PI / 360.)));
|
|
|
|
|
|
|
|
renderSetAspect(v1, yxaspect);
|
2019-09-19 22:42:45 +00:00
|
|
|
int cX = gView->pSprite->x;
|
|
|
|
int cY = gView->pSprite->y;
|
2019-10-21 19:46:41 +00:00
|
|
|
int cZ = gView->zView;
|
2019-12-30 18:29:32 +00:00
|
|
|
int zDelta = gView->zWeapon - gView->zView - (12 << 8);
|
2019-09-19 22:42:45 +00:00
|
|
|
fix16_t cA = gView->q16ang;
|
|
|
|
fix16_t q16horiz = gView->q16horiz;
|
|
|
|
fix16_t q16slopehoriz = gView->q16slopehoriz;
|
2019-10-21 19:46:41 +00:00
|
|
|
int v74 = gView->bobWidth;
|
|
|
|
int v8c = gView->bobHeight;
|
|
|
|
int v4c = gView->swayWidth;
|
|
|
|
int v48 = gView->swayHeight;
|
2019-09-19 22:42:45 +00:00
|
|
|
int nSectnum = gView->pSprite->sectnum;
|
2019-10-22 00:15:24 +00:00
|
|
|
if (cl_interpolate)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
if (numplayers > 1 && gView == gMe && gPrediction && gMe->pXSprite->health > 0)
|
|
|
|
{
|
|
|
|
nSectnum = predict.at68;
|
|
|
|
cX = interpolate(predictOld.at50, predict.at50, gInterpolate);
|
|
|
|
cY = interpolate(predictOld.at54, predict.at54, gInterpolate);
|
|
|
|
cZ = interpolate(predictOld.at38, predict.at38, gInterpolate);
|
|
|
|
zDelta = interpolate(predictOld.at34, predict.at34, gInterpolate);
|
|
|
|
cA = interpolateangfix16(predictOld.at30, predict.at30, gInterpolate);
|
|
|
|
q16horiz = interpolate(predictOld.at24, predict.at24, gInterpolate);
|
|
|
|
q16slopehoriz = interpolate(predictOld.at28, predict.at28, gInterpolate);
|
|
|
|
v74 = interpolate(predictOld.atc, predict.atc, gInterpolate);
|
|
|
|
v8c = interpolate(predictOld.at8, predict.at8, gInterpolate);
|
|
|
|
v4c = interpolate(predictOld.at1c, predict.at1c, gInterpolate);
|
|
|
|
v48 = interpolate(predictOld.at18, predict.at18, gInterpolate);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
VIEW* pView = &gPrevView[gViewIndex];
|
2019-09-19 22:42:45 +00:00
|
|
|
cX = interpolate(pView->at50, cX, gInterpolate);
|
|
|
|
cY = interpolate(pView->at54, cY, gInterpolate);
|
|
|
|
cZ = interpolate(pView->at38, cZ, gInterpolate);
|
|
|
|
zDelta = interpolate(pView->at34, zDelta, gInterpolate);
|
|
|
|
cA = interpolateangfix16(pView->at30, cA, gInterpolate);
|
|
|
|
q16horiz = interpolate(pView->at24, q16horiz, gInterpolate);
|
|
|
|
q16slopehoriz = interpolate(pView->at28, q16slopehoriz, gInterpolate);
|
|
|
|
v74 = interpolate(pView->atc, v74, gInterpolate);
|
|
|
|
v8c = interpolate(pView->at8, v8c, gInterpolate);
|
|
|
|
v4c = interpolate(pView->at1c, v4c, gInterpolate);
|
|
|
|
v48 = interpolate(pView->at18, v48, gInterpolate);
|
|
|
|
}
|
|
|
|
}
|
2020-01-30 13:05:34 +00:00
|
|
|
if (gView == gMe && (numplayers <= 1 || gPrediction) && gView->pXSprite->health != 0 && !VanillaMode())
|
|
|
|
{
|
2020-04-01 11:55:36 +00:00
|
|
|
int upAngle = 289;
|
|
|
|
int downAngle = -347;
|
2020-01-30 13:05:34 +00:00
|
|
|
fix16_t q16look;
|
|
|
|
cA = gViewAngle;
|
|
|
|
q16look = gViewLook;
|
|
|
|
q16horiz = fix16_from_float(100.f * tanf(fix16_to_float(q16look) * fPI / 1024.f));
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
viewUpdateShake();
|
|
|
|
q16horiz += fix16_from_int(shakeHoriz);
|
|
|
|
cA += fix16_from_int(shakeAngle);
|
|
|
|
cX += shakeX;
|
|
|
|
cY += shakeY;
|
|
|
|
cZ += shakeZ;
|
|
|
|
v4c += shakeBobX;
|
|
|
|
v48 += shakeBobY;
|
2019-12-30 18:29:32 +00:00
|
|
|
q16horiz += fix16_from_int(mulscale30(0x40000000 - Cos(gView->tiltEffect << 2), 30));
|
2019-09-19 22:42:45 +00:00
|
|
|
if (gViewPos == 0)
|
|
|
|
{
|
2019-10-22 00:15:24 +00:00
|
|
|
if (cl_viewhbob)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
cX -= mulscale30(v74, Sin(fix16_to_int(cA))) >> 4;
|
|
|
|
cY += mulscale30(v74, Cos(fix16_to_int(cA))) >> 4;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-10-22 00:15:24 +00:00
|
|
|
if (cl_viewvbob)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
cZ += v8c;
|
|
|
|
}
|
2019-10-22 00:15:24 +00:00
|
|
|
if (cl_slopetilting)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
q16horiz += q16slopehoriz;
|
|
|
|
}
|
2019-12-30 18:29:32 +00:00
|
|
|
cZ += fix16_to_int(q16horiz * 10);
|
2019-09-19 22:42:45 +00:00
|
|
|
cameradist = -1;
|
2019-09-07 16:39:26 +00:00
|
|
|
cameraclock = (int)totalclock;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CalcPosition(gView->pSprite, (int*)&cX, (int*)&cY, (int*)&cZ, &nSectnum, fix16_to_int(cA), q16horiz);
|
|
|
|
}
|
|
|
|
CheckLink((int*)&cX, (int*)&cY, (int*)&cZ, &nSectnum);
|
|
|
|
int v78 = interpolateang(gScreenTiltO, gScreenTilt, gInterpolate);
|
2020-08-02 17:00:32 +00:00
|
|
|
uint8_t v14 = 0;
|
|
|
|
uint8_t v10 = 0;
|
2019-10-19 19:11:39 +00:00
|
|
|
bool bDelirium = powerupCheck(gView, kPwUpDeliriumShroom) > 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
static bool bDeliriumOld = false;
|
2020-03-29 06:36:39 +00:00
|
|
|
//int tiltcs, tiltdim;
|
2020-08-02 17:00:32 +00:00
|
|
|
uint8_t v4 = powerupCheck(gView, kPwUpCrystalBall) > 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
#ifdef USE_OPENGL
|
|
|
|
renderSetRollAngle(0);
|
|
|
|
#endif
|
|
|
|
if (v78 || bDelirium)
|
|
|
|
{
|
2020-03-29 13:54:02 +00:00
|
|
|
renderSetRollAngle(v78);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else if (v4 && gNetPlayers > 1)
|
|
|
|
{
|
2020-03-29 06:36:39 +00:00
|
|
|
#if 0 // needs to be redone for pure hardware rendering.
|
2019-12-30 18:29:32 +00:00
|
|
|
int tmp = ((int)totalclock / 240) % (gNetPlayers - 1);
|
2019-09-19 22:42:45 +00:00
|
|
|
int i = connecthead;
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (i == gViewIndex)
|
|
|
|
i = connectpoint2[i];
|
|
|
|
if (tmp == 0)
|
|
|
|
break;
|
|
|
|
i = connectpoint2[i];
|
|
|
|
tmp--;
|
|
|
|
}
|
2019-12-30 18:29:32 +00:00
|
|
|
PLAYER* pOther = &gPlayer[i];
|
2019-09-19 22:42:45 +00:00
|
|
|
//othercameraclock = gGameClock;
|
2019-10-11 21:31:59 +00:00
|
|
|
if (!tileData(4079))
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-05-24 10:31:38 +00:00
|
|
|
tileAllocTile(4079, 128, 128);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-03-29 06:36:39 +00:00
|
|
|
r enderSetTarget(4079, 128, 128);
|
2019-09-19 22:42:45 +00:00
|
|
|
renderSetAspect(65536, 78643);
|
|
|
|
int vd8 = pOther->pSprite->x;
|
|
|
|
int vd4 = pOther->pSprite->y;
|
2019-10-21 19:46:41 +00:00
|
|
|
int vd0 = pOther->zView;
|
2019-09-19 22:42:45 +00:00
|
|
|
int vcc = pOther->pSprite->sectnum;
|
|
|
|
int v50 = pOther->pSprite->ang;
|
|
|
|
int v54 = 0;
|
2019-10-21 19:46:41 +00:00
|
|
|
if (pOther->flickerEffect)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
int nValue = ClipHigh(pOther->flickerEffect * 8, 2000);
|
|
|
|
v54 += QRandom2(nValue >> 8);
|
|
|
|
v50 += QRandom2(nValue >> 8);
|
|
|
|
vd8 += QRandom2(nValue >> 4);
|
|
|
|
vd4 += QRandom2(nValue >> 4);
|
2019-09-19 22:42:45 +00:00
|
|
|
vd0 += QRandom2(nValue);
|
|
|
|
}
|
2019-10-21 19:46:41 +00:00
|
|
|
if (pOther->quakeEffect)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
int nValue = ClipHigh(pOther->quakeEffect * 8, 2000);
|
2019-09-19 22:42:45 +00:00
|
|
|
v54 += QRandom2(nValue >> 8);
|
|
|
|
v50 += QRandom2(nValue >> 8);
|
|
|
|
vd8 += QRandom2(nValue >> 4);
|
|
|
|
vd4 += QRandom2(nValue >> 4);
|
|
|
|
vd0 += QRandom2(nValue);
|
|
|
|
}
|
|
|
|
CalcOtherPosition(pOther->pSprite, &vd8, &vd4, &vd0, &vcc, v50, 0);
|
|
|
|
CheckLink(&vd8, &vd4, &vd0, &vcc);
|
|
|
|
if (IsUnderwaterSector(vcc))
|
|
|
|
{
|
|
|
|
v14 = 10;
|
|
|
|
}
|
2019-12-30 18:29:32 +00:00
|
|
|
memcpy(bakMirrorGotpic, gotpic + 510, 2);
|
|
|
|
memcpy(gotpic + 510, otherMirrorGotpic, 2);
|
2020-06-21 03:08:46 +00:00
|
|
|
g_visibility = (int32_t)(ClipLow(gVisibility - 32 * pOther->visibility, 0));
|
2019-09-19 22:42:45 +00:00
|
|
|
int vc4, vc8;
|
|
|
|
getzsofslope(vcc, vd8, vd4, &vc8, &vc4);
|
|
|
|
if (vd0 >= vc4)
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
vd0 = vc4 - (gUpperLink[vcc] >= 0 ? 0 : (8 << 8));
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
if (vd0 <= vc8)
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
vd0 = vc8 + (gLowerLink[vcc] >= 0 ? 0 : (8 << 8));
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
v54 = ClipRange(v54, -200, 200);
|
2019-12-30 18:29:32 +00:00
|
|
|
RORHACKOTHER:
|
2019-09-19 22:42:45 +00:00
|
|
|
int ror_status[16];
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
ror_status[i] = TestBitString(gotpic, 4080 + i);
|
2019-06-29 17:48:05 +00:00
|
|
|
yax_preparedrawrooms();
|
2019-09-08 14:29:17 +00:00
|
|
|
DrawMirrors(vd8, vd4, vd0, fix16_from_int(v50), fix16_from_int(v54 + defaultHoriz), gInterpolate, -1);
|
2019-09-19 22:42:45 +00:00
|
|
|
drawrooms(vd8, vd4, vd0, v50, v54 + defaultHoriz, vcc);
|
2019-06-29 17:48:05 +00:00
|
|
|
yax_drawrooms(viewProcessSprites, vcc, 0, gInterpolate);
|
2019-09-19 22:42:45 +00:00
|
|
|
bool do_ror_hack = false;
|
|
|
|
for (int i = 0; i < 16; i++)
|
2019-09-07 16:39:26 +00:00
|
|
|
if (ror_status[i] != TestBitString(gotpic, 4080 + i))
|
2019-09-19 22:42:45 +00:00
|
|
|
do_ror_hack = true;
|
|
|
|
if (do_ror_hack)
|
2020-05-22 16:00:48 +00:00
|
|
|
{
|
|
|
|
spritesortcnt = 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
goto RORHACKOTHER;
|
2020-05-22 16:00:48 +00:00
|
|
|
}
|
|
|
|
memcpy(otherMirrorGotpic, gotpic+510, 2);
|
|
|
|
memcpy(gotpic+510, bakMirrorGotpic, 2);
|
2019-06-29 17:48:05 +00:00
|
|
|
viewProcessSprites(vd8, vd4, vd0, v50, gInterpolate);
|
2019-09-19 22:42:45 +00:00
|
|
|
renderDrawMasks();
|
|
|
|
renderRestoreTarget();
|
2020-03-29 06:36:39 +00:00
|
|
|
#endif
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-09-07 16:39:26 +00:00
|
|
|
othercameraclock = (int)totalclock;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bDelirium)
|
|
|
|
{
|
|
|
|
deliriumTilt = 0;
|
|
|
|
deliriumTurn = 0;
|
|
|
|
deliriumPitch = 0;
|
|
|
|
}
|
2019-10-07 19:29:52 +00:00
|
|
|
int nSprite = headspritestat[kStatExplosion];
|
2019-09-19 22:42:45 +00:00
|
|
|
int unk = 0;
|
|
|
|
while (nSprite >= 0)
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
spritetype* pSprite = &sprite[nSprite];
|
2019-09-19 22:42:45 +00:00
|
|
|
int nXSprite = pSprite->extra;
|
|
|
|
dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
|
2019-12-30 18:29:32 +00:00
|
|
|
XSPRITE* pXSprite = &xsprite[nXSprite];
|
2019-09-19 22:42:45 +00:00
|
|
|
if (TestBitString(gotsector, pSprite->sectnum))
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
unk += pXSprite->data3 * 32;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
nSprite = nextspritestat[nSprite];
|
|
|
|
}
|
2019-10-07 19:29:52 +00:00
|
|
|
nSprite = headspritestat[kStatProjectile];
|
2019-10-11 21:59:39 +00:00
|
|
|
while (nSprite >= 0) {
|
2019-12-30 18:29:32 +00:00
|
|
|
spritetype* pSprite = &sprite[nSprite];
|
2019-10-11 21:59:39 +00:00
|
|
|
switch (pSprite->type) {
|
2019-12-30 18:29:32 +00:00
|
|
|
case kMissileFlareRegular:
|
|
|
|
case kMissileTeslaAlt:
|
|
|
|
case kMissileFlareAlt:
|
|
|
|
case kMissileTeslaRegular:
|
|
|
|
if (TestBitString(gotsector, pSprite->sectnum)) unk += 256;
|
|
|
|
break;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
nSprite = nextspritestat[nSprite];
|
|
|
|
}
|
2020-06-21 03:08:46 +00:00
|
|
|
g_visibility = (int32_t)(ClipLow(gVisibility - 32 * gView->visibility - unk, 0));
|
2019-09-19 22:42:45 +00:00
|
|
|
cA = (cA + interpolateangfix16(fix16_from_int(deliriumTurnO), fix16_from_int(deliriumTurn), gInterpolate)) & 0x7ffffff;
|
|
|
|
int vfc, vf8;
|
|
|
|
getzsofslope(nSectnum, cX, cY, &vfc, &vf8);
|
|
|
|
if (cZ >= vf8)
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
cZ = vf8 - (gUpperLink[nSectnum] >= 0 ? 0 : (8 << 8));
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
if (cZ <= vfc)
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
cZ = vfc + (gLowerLink[nSectnum] >= 0 ? 0 : (8 << 8));
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-03-31 21:30:54 +00:00
|
|
|
q16horiz = ClipRange(q16horiz, fix16_from_int(-200), fix16_from_int(200));
|
2019-12-30 18:29:32 +00:00
|
|
|
RORHACK:
|
2019-09-19 22:42:45 +00:00
|
|
|
int ror_status[16];
|
|
|
|
for (int i = 0; i < 16; i++)
|
2019-12-30 18:29:32 +00:00
|
|
|
ror_status[i] = TestBitString(gotpic, 4080 + i);
|
2019-09-19 22:42:45 +00:00
|
|
|
fix16_t deliriumPitchI = interpolate(fix16_from_int(deliriumPitchO), fix16_from_int(deliriumPitch), gInterpolate);
|
2019-09-08 14:29:17 +00:00
|
|
|
DrawMirrors(cX, cY, cZ, cA, q16horiz + fix16_from_int(defaultHoriz) + deliriumPitchI, gInterpolate, gViewIndex);
|
2019-09-19 22:42:45 +00:00
|
|
|
int bakCstat = gView->pSprite->cstat;
|
|
|
|
if (gViewPos == 0)
|
|
|
|
{
|
|
|
|
gView->pSprite->cstat |= 32768;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gView->pSprite->cstat |= 514;
|
|
|
|
}
|
2020-07-27 17:45:34 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
renderDrawRoomsQ16(cX, cY, cZ, cA, q16horiz + fix16_from_int(defaultHoriz) + deliriumPitchI, nSectnum);
|
2019-06-29 17:48:05 +00:00
|
|
|
viewProcessSprites(cX, cY, cZ, fix16_to_int(cA), gInterpolate);
|
2019-09-19 22:42:45 +00:00
|
|
|
bool do_ror_hack = false;
|
|
|
|
for (int i = 0; i < 16; i++)
|
2019-12-30 18:29:32 +00:00
|
|
|
if (ror_status[i] != TestBitString(gotpic, 4080 + i))
|
2019-09-19 22:42:45 +00:00
|
|
|
do_ror_hack = true;
|
|
|
|
if (do_ror_hack)
|
|
|
|
{
|
|
|
|
gView->pSprite->cstat = bakCstat;
|
2020-05-22 16:00:48 +00:00
|
|
|
spritesortcnt = 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
goto RORHACK;
|
|
|
|
}
|
2019-06-29 18:15:27 +00:00
|
|
|
sub_5571C(1);
|
|
|
|
int nSpriteSortCnt = spritesortcnt;
|
|
|
|
renderDrawMasks();
|
|
|
|
spritesortcnt = nSpriteSortCnt;
|
|
|
|
sub_5571C(0);
|
2019-09-19 22:42:45 +00:00
|
|
|
sub_557C4(cX, cY, gInterpolate);
|
|
|
|
renderDrawMasks();
|
|
|
|
gView->pSprite->cstat = bakCstat;
|
|
|
|
|
2020-01-25 14:27:46 +00:00
|
|
|
if ((v78 || bDelirium) && !sceneonly)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-03-29 13:54:02 +00:00
|
|
|
if (videoGetRenderMode() == REND_POLYMOST && gDeliriumBlur)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-03-29 13:54:02 +00:00
|
|
|
// todo: Implement using modern techniques instead of relying on deprecated old stuff that isn't well supported anymore.
|
|
|
|
/* names broken up so that searching for GL keywords won't find them anymore
|
|
|
|
if (!bDeliriumOld)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-03-29 13:54:02 +00:00
|
|
|
g lAccum(GL_LOAD, 1.f);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-03-29 13:54:02 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const float fBlur = pow(1.f/3.f, 30.f/g_frameRate);
|
|
|
|
g lAccum(GL _MULT, fBlur);
|
|
|
|
g lAccum(GL _ACCUM, 1.f-fBlur);
|
|
|
|
g lAccum(GL _RETURN, 1.f);
|
|
|
|
}
|
|
|
|
*/
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bDeliriumOld = bDelirium && gDeliriumBlur;
|
|
|
|
|
|
|
|
if (r_usenewaspect)
|
|
|
|
newaspect_enable = 0;
|
|
|
|
renderSetAspect(viewingRange, yxAspect);
|
2019-12-30 18:29:32 +00:00
|
|
|
int nClipDist = gView->pSprite->clipdist << 2;
|
2019-09-19 22:42:45 +00:00
|
|
|
int ve8, vec, vf0, vf4;
|
|
|
|
GetZRange(gView->pSprite, &vf4, &vf0, &vec, &ve8, nClipDist, 0);
|
2020-01-25 14:27:46 +00:00
|
|
|
if (sceneonly) return;
|
2019-09-19 22:42:45 +00:00
|
|
|
#if 0
|
|
|
|
int tmpSect = nSectnum;
|
2019-06-28 12:24:46 +00:00
|
|
|
if ((vf0 & 0xc000) == 0x4000)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
tmpSect = vf0 & (kMaxWalls - 1);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-12-30 18:29:32 +00:00
|
|
|
int v8 = byte_1CE5C2 > 0 && (sector[tmpSect].ceilingstat & 1);
|
2019-09-19 22:42:45 +00:00
|
|
|
if (gWeather.at12d8 > 0 || v8)
|
|
|
|
{
|
|
|
|
gWeather.Draw(cX, cY, cZ, cA, q16horiz + defaultHoriz + deliriumPitch, gWeather.at12d8);
|
|
|
|
if (v8)
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
gWeather.at12d8 = ClipRange(delta * 8 + gWeather.at12d8, 0, 4095);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-30 18:29:32 +00:00
|
|
|
gWeather.at12d8 = ClipRange(gWeather.at12d8 - delta * 64, 0, 4095);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2020-08-02 17:00:32 +00:00
|
|
|
hudDraw(gView, nSectnum, defaultHoriz, v4c, v48, zDelta, basepal);
|
2019-12-30 18:29:32 +00:00
|
|
|
}
|
2020-07-27 21:29:10 +00:00
|
|
|
UpdateDacs(0, true); // keep the view palette active only for the actual 3D view and its overlays.
|
2019-09-19 22:42:45 +00:00
|
|
|
if (gViewMode == 4)
|
|
|
|
{
|
|
|
|
gViewMap.sub_25DB0(gView->pSprite);
|
|
|
|
}
|
|
|
|
viewDrawInterface(delta);
|
2019-10-21 19:46:41 +00:00
|
|
|
int zn = ((gView->zWeapon-gView->zView-(12<<8))>>7)+220;
|
2019-09-19 22:42:45 +00:00
|
|
|
PLAYER *pPSprite = &gPlayer[gMe->pSprite->type-kDudePlayer1];
|
2020-02-06 08:48:45 +00:00
|
|
|
if (IsPlayerSprite(gMe->pSprite) && pPSprite->hand == 1)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
//static int lastClock;
|
2020-07-27 21:29:10 +00:00
|
|
|
gChoke.sub_84110(160, zn, 0);
|
2019-09-19 22:42:45 +00:00
|
|
|
//if ((gGameClock % 5) == 0 && gGameClock != lastClock)
|
|
|
|
//{
|
2019-10-21 19:46:41 +00:00
|
|
|
// gChoke.swayV(pPSprite);
|
2019-09-19 22:42:45 +00:00
|
|
|
//}
|
|
|
|
//lastClock = gGameClock;
|
|
|
|
}
|
2020-08-02 06:39:51 +00:00
|
|
|
#if 0
|
2019-09-19 22:42:45 +00:00
|
|
|
if (byte_1A76C6)
|
|
|
|
{
|
|
|
|
DrawStatSprite(2048, xdim-15, 20);
|
|
|
|
}
|
2020-08-02 06:39:51 +00:00
|
|
|
#endif
|
2019-09-19 22:42:45 +00:00
|
|
|
CalcFrameRate();
|
2019-12-23 19:55:12 +00:00
|
|
|
|
2019-10-27 16:55:14 +00:00
|
|
|
viewDrawMapTitle();
|
|
|
|
viewDrawAimedPlayerName();
|
2020-05-29 01:20:40 +00:00
|
|
|
if (paused)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-12-09 01:01:30 +00:00
|
|
|
viewDrawText(1, GStrings("TXTB_PAUSED"), 160, 10, 0, 0, 1, 0);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else if (gView != gMe)
|
|
|
|
{
|
2019-12-29 15:35:51 +00:00
|
|
|
FStringf gTempStr("] %s [", gProfile[gView->nPlayer].name);
|
2019-09-19 22:42:45 +00:00
|
|
|
viewDrawText(0, gTempStr, 160, 10, 0, 0, 1, 0);
|
|
|
|
}
|
|
|
|
if (errMsg[0])
|
|
|
|
{
|
|
|
|
viewDrawText(0, errMsg, 160, 20, 0, 0, 1, 0);
|
|
|
|
}
|
2019-10-22 00:15:24 +00:00
|
|
|
if (cl_interpolate)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
RestoreInterpolations();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 20:20:46 +00:00
|
|
|
bool GameInterface::GenerateSavePic()
|
|
|
|
{
|
|
|
|
viewDrawScreen(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
#define LOW_FPS 60
|
|
|
|
#define SLOW_FRAME_TIME 20
|
|
|
|
|
|
|
|
#if defined GEKKO
|
|
|
|
# define FPS_YOFFSET 16
|
|
|
|
#else
|
|
|
|
# define FPS_YOFFSET 0
|
|
|
|
#endif
|
|
|
|
|
2019-11-10 10:42:25 +00:00
|
|
|
FString GameInterface::statFPS(void)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-11-10 10:42:25 +00:00
|
|
|
FString output;
|
2019-09-19 22:42:45 +00:00
|
|
|
static int32_t frameCount;
|
|
|
|
static double cumulativeFrameDelay;
|
|
|
|
static double lastFrameTime;
|
|
|
|
static float lastFPS, minFPS = FLT_MAX, maxFPS;
|
|
|
|
static double minGameUpdate = DBL_MAX, maxGameUpdate;
|
|
|
|
|
|
|
|
double frameTime = timerGetHiTicks();
|
|
|
|
double frameDelay = frameTime - lastFrameTime;
|
|
|
|
cumulativeFrameDelay += frameDelay;
|
|
|
|
|
|
|
|
if (frameDelay >= 0)
|
|
|
|
{
|
|
|
|
int32_t x = (xdim <= 640);
|
|
|
|
|
2019-11-10 10:42:25 +00:00
|
|
|
//if (r_showfps)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-11-10 10:42:25 +00:00
|
|
|
output.AppendFormat("%.1f ms, %5.1f fps\n", frameDelay, lastFPS);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-10-22 23:04:07 +00:00
|
|
|
if (r_showfps > 1)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-11-10 10:42:25 +00:00
|
|
|
output.AppendFormat("max: %5.1f fps\n", maxFPS);
|
|
|
|
output.AppendFormat("min: %5.1f fps\n", minFPS);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-10-22 23:04:07 +00:00
|
|
|
if (r_showfps > 2)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
if (g_gameUpdateTime > maxGameUpdate) maxGameUpdate = g_gameUpdateTime;
|
|
|
|
if (g_gameUpdateTime < minGameUpdate) minGameUpdate = g_gameUpdateTime;
|
|
|
|
|
2019-11-10 10:42:25 +00:00
|
|
|
output.AppendFormat("Game Update: %2.2f ms + draw: %2.2f ms\n", g_gameUpdateTime, g_gameUpdateAndDrawTime - g_gameUpdateTime);
|
|
|
|
output.AppendFormat("GU min/max/avg: %5.2f/%5.2f/%5.2f ms\n", minGameUpdate, maxGameUpdate, g_gameUpdateAvgTime);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-11-10 10:42:25 +00:00
|
|
|
output.AppendFormat("bufferjitter: %i\n", gBufferJitter);
|
2019-09-19 22:42:45 +00:00
|
|
|
#if 0
|
2019-11-10 10:42:25 +00:00
|
|
|
output.AppendFormat("G_MoveActors(): %.3f ms\n", g_moveActorsTime);
|
|
|
|
output.AppendFormat("G_MoveWorld(): %.3f ms\n", g_moveWorldTime);
|
2019-09-19 22:42:45 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
// lag meter
|
|
|
|
if (g_netClientPeer)
|
|
|
|
{
|
2019-11-10 10:42:25 +00:00
|
|
|
output.AppendFormat("%d +- %d ms\n", (g_netClientPeer->lastRoundTripTime + g_netClientPeer->roundTripTime)/2,
|
2019-09-19 22:42:45 +00:00
|
|
|
(g_netClientPeer->lastRoundTripTimeVariance + g_netClientPeer->roundTripTimeVariance)/2);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cumulativeFrameDelay >= 1000.0)
|
|
|
|
{
|
|
|
|
lastFPS = 1000.f * frameCount / cumulativeFrameDelay;
|
|
|
|
g_frameRate = Blrintf(lastFPS);
|
|
|
|
frameCount = 0;
|
|
|
|
cumulativeFrameDelay = 0.0;
|
|
|
|
|
2019-10-22 23:04:07 +00:00
|
|
|
if (r_showfps > 1)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
if (lastFPS > maxFPS) maxFPS = lastFPS;
|
|
|
|
if (lastFPS < minFPS) minFPS = lastFPS;
|
|
|
|
|
|
|
|
static int secondCounter;
|
|
|
|
|
2019-10-22 23:04:07 +00:00
|
|
|
if (++secondCounter >= r_showfpsperiod)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
maxFPS = (lastFPS + maxFPS) * .5f;
|
|
|
|
minFPS = (lastFPS + minFPS) * .5f;
|
|
|
|
maxGameUpdate = (g_gameUpdateTime + maxGameUpdate) * 0.5;
|
|
|
|
minGameUpdate = (g_gameUpdateTime + minGameUpdate) * 0.5;
|
|
|
|
secondCounter = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
frameCount++;
|
|
|
|
}
|
|
|
|
lastFrameTime = frameTime;
|
2019-11-10 10:42:25 +00:00
|
|
|
return output;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-23 19:55:12 +00:00
|
|
|
FString GameInterface::GetCoordString()
|
|
|
|
{
|
|
|
|
return "Player pos is unknown"; // todo: output at least something useful.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
class ViewLoadSave : public LoadSave {
|
|
|
|
public:
|
|
|
|
void Load(void);
|
|
|
|
void Save(void);
|
|
|
|
};
|
|
|
|
|
|
|
|
static ViewLoadSave *myLoadSave;
|
|
|
|
|
|
|
|
static int messageTime;
|
|
|
|
static char message[256];
|
|
|
|
|
|
|
|
void ViewLoadSave::Load(void)
|
|
|
|
{
|
|
|
|
Read(&messageTime, sizeof(messageTime));
|
|
|
|
Read(message, sizeof(message));
|
|
|
|
Read(otherMirrorGotpic, sizeof(otherMirrorGotpic));
|
|
|
|
Read(bakMirrorGotpic, sizeof(bakMirrorGotpic));
|
|
|
|
Read(&gScreenTilt, sizeof(gScreenTilt));
|
|
|
|
Read(&deliriumTilt, sizeof(deliriumTilt));
|
|
|
|
Read(&deliriumTurn, sizeof(deliriumTurn));
|
|
|
|
Read(&deliriumPitch, sizeof(deliriumPitch));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewLoadSave::Save(void)
|
|
|
|
{
|
|
|
|
Write(&messageTime, sizeof(messageTime));
|
|
|
|
Write(message, sizeof(message));
|
|
|
|
Write(otherMirrorGotpic, sizeof(otherMirrorGotpic));
|
|
|
|
Write(bakMirrorGotpic, sizeof(bakMirrorGotpic));
|
|
|
|
Write(&gScreenTilt, sizeof(gScreenTilt));
|
|
|
|
Write(&deliriumTilt, sizeof(deliriumTilt));
|
|
|
|
Write(&deliriumTurn, sizeof(deliriumTurn));
|
|
|
|
Write(&deliriumPitch, sizeof(deliriumPitch));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewLoadSaveConstruct(void)
|
|
|
|
{
|
|
|
|
myLoadSave = new ViewLoadSave();
|
|
|
|
}
|
2019-09-22 06:39:22 +00:00
|
|
|
|
|
|
|
END_BLD_NS
|