mirror of
https://github.com/DrBeef/Raze.git
synced 2025-02-02 05:43:05 +00:00
84173ee09b
The main bulk of this is the new start screen code. To make this work in Raze some more work on the startup procedure is needed. What this does provide is support for the DOS end-of-game text screens in Duke and SW on non-Windows systems.
838 lines
20 KiB
C++
838 lines
20 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 1997, 2005 - 3D Realms Entertainment
|
|
|
|
This file is part of Shadow Warrior version 1.2
|
|
|
|
Shadow Warrior 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.
|
|
|
|
Original Source: 1997 - Frank Maddin and Jim Norwood
|
|
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "ns.h"
|
|
|
|
#define MAIN
|
|
#define QUIET
|
|
#include "build.h"
|
|
#include "names2.h"
|
|
#include "panel.h"
|
|
#include "game.h"
|
|
#include "swactor.h"
|
|
#include "interpso.h"
|
|
#include "tags.h"
|
|
#include "sector.h"
|
|
#include "sprite.h"
|
|
#include "weapon.h"
|
|
#include "player.h"
|
|
#include "lists.h"
|
|
#include "network.h"
|
|
#include "pal.h"
|
|
#include "automap.h"
|
|
#include "statusbar.h"
|
|
#include "texturemanager.h"
|
|
#include "st_start.h"
|
|
#include "i_interface.h"
|
|
#include "psky.h"
|
|
#include "startscreen.h"
|
|
|
|
|
|
|
|
#include "menus.h"
|
|
|
|
#include "gamecontrol.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "misc.h"
|
|
#include "break.h"
|
|
#include "light.h"
|
|
#include "misc.h"
|
|
#include "jsector.h"
|
|
|
|
#include "gameconfigfile.h"
|
|
#include "printf.h"
|
|
#include "m_argv.h"
|
|
#include "debugbreak.h"
|
|
#include "razemenu.h"
|
|
#include "raze_music.h"
|
|
#include "statistics.h"
|
|
#include "gstrings.h"
|
|
#include "mapinfo.h"
|
|
#include "v_video.h"
|
|
#include "raze_sound.h"
|
|
#include "secrets.h"
|
|
|
|
#include "screenjob_.h"
|
|
#include "inputstate.h"
|
|
#include "gamestate.h"
|
|
#include "d_net.h"
|
|
#include "v_draw.h"
|
|
#include "interpolate.h"
|
|
|
|
//#include "crc32.h"
|
|
|
|
CVAR(Bool, sw_ninjahack, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_SERVERINFO);
|
|
CVAR(Bool, sw_darts, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
|
CVAR(Bool, sw_bunnyrockets, false, CVAR_SERVERINFO | CVAR_CHEAT); // This is a cheat, so don't save.
|
|
|
|
BEGIN_SW_NS
|
|
|
|
IMPLEMENT_CLASS(DSWActor, false, true)
|
|
IMPLEMENT_POINTERS_START(DSWActor)
|
|
IMPLEMENT_POINTER(ownerActor)
|
|
IMPLEMENT_POINTER(user.lowActor)
|
|
IMPLEMENT_POINTER(user.lowActor)
|
|
IMPLEMENT_POINTER(user.highActor)
|
|
IMPLEMENT_POINTER(user.targetActor)
|
|
IMPLEMENT_POINTER(user.flameActor)
|
|
IMPLEMENT_POINTER(user.attachActor)
|
|
IMPLEMENT_POINTER(user.WpnGoalActor)
|
|
IMPLEMENT_POINTERS_END
|
|
|
|
void MarkSOInterp();
|
|
|
|
void markgcroots()
|
|
{
|
|
MarkSOInterp();
|
|
GC::MarkArray(StarQueue, MAX_STAR_QUEUE);
|
|
GC::MarkArray(HoleQueue, MAX_HOLE_QUEUE);
|
|
GC::MarkArray(WallBloodQueue, MAX_WALLBLOOD_QUEUE);
|
|
GC::MarkArray(FloorBloodQueue, MAX_FLOORBLOOD_QUEUE);
|
|
GC::MarkArray(GenericQueue, MAX_GENERIC_QUEUE);
|
|
GC::MarkArray(LoWangsQueue, MAX_LOWANGS_QUEUE);
|
|
GC::MarkArray(BossSpriteNum, 3);
|
|
for (auto& pl : Player)
|
|
{
|
|
GC::Mark(pl.actor);
|
|
GC::Mark(pl.lowActor);
|
|
GC::Mark(pl.highActor);
|
|
GC::Mark(pl.remoteActor);
|
|
GC::Mark(pl.PlayerUnderActor);
|
|
GC::Mark(pl.KillerActor);
|
|
GC::Mark(pl.HitBy);
|
|
GC::Mark(pl.last_camera_act);
|
|
}
|
|
for (auto& so : SectorObject)
|
|
{
|
|
GC::Mark(so.controller);
|
|
GC::Mark(so.sp_child);
|
|
GC::MarkArray(so.so_actors, MAX_SO_SPRITE);
|
|
GC::Mark(so.match_event_actor);
|
|
}
|
|
for (int i = 0; i < AnimCnt; i++)
|
|
{
|
|
GC::Mark(Anim[i].animactor);
|
|
}
|
|
for (auto& mir : mirror)
|
|
{
|
|
GC::Mark(mir.cameraActor);
|
|
GC::Mark(mir.camspriteActor);
|
|
}
|
|
}
|
|
|
|
|
|
void pClearSpriteList(PLAYER* pp);
|
|
|
|
extern int sw_snd_scratch;
|
|
|
|
int GameVersion = 20;
|
|
|
|
bool NoMeters = false;
|
|
int FinishAnim = 0;
|
|
bool ReloadPrompt = false;
|
|
bool NewGame = false;
|
|
//Miscellaneous variables
|
|
bool FinishedLevel = false;
|
|
short screenpeek = 0;
|
|
|
|
int GodMode = false;
|
|
short Skill = 2;
|
|
int TotalKillable;
|
|
|
|
const GAME_SET gs_defaults =
|
|
{
|
|
// Network game settings
|
|
0, // GameType
|
|
0, // Monsters
|
|
false, // HurtTeammate
|
|
true, // SpawnMarkers Markers
|
|
false, // TeamPlay
|
|
0, // Kill Limit
|
|
0, // Time Limit
|
|
0, // Color
|
|
true, // nuke
|
|
};
|
|
GAME_SET gs;
|
|
|
|
bool PlayerTrackingMode = false;
|
|
bool SlowMode = false;
|
|
|
|
bool DebugOperate = false;
|
|
void LoadingLevelScreen(void);
|
|
|
|
uint8_t FakeMultiNumPlayers;
|
|
|
|
int totalsynctics;
|
|
|
|
int OrigCommPlayers=0;
|
|
extern uint8_t CommPlayers;
|
|
extern bool CommEnabled;
|
|
|
|
bool CameraTestMode = false;
|
|
|
|
char ds[645]; // debug string
|
|
|
|
extern short NormalVisibility;
|
|
bool CommandSetup = false;
|
|
|
|
char buffer[80], ch;
|
|
|
|
uint8_t DebugPrintColor = 255;
|
|
|
|
FString ThemeSongs[6];
|
|
int ThemeTrack[6];
|
|
|
|
/// L O C A L P R O T O T Y P E S /////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define x(a, b) registerName(#a, b);
|
|
static void SetTileNames()
|
|
{
|
|
auto registerName = [](const char* name, int index)
|
|
{
|
|
TexMan.AddAlias(name, tileGetTexture(index));
|
|
TileFiles.addName(name, index);
|
|
};
|
|
#include "namelist.h"
|
|
}
|
|
#undef x
|
|
|
|
void GameInterface::LoadGameTextures()
|
|
{
|
|
LoadKVXFromScript("swvoxfil.txt"); // Load voxels from script file
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void GameInterface::app_init()
|
|
{
|
|
GC::AddMarkerFunc(markgcroots);
|
|
|
|
GameTicRate = TICS_PER_SEC / synctics;
|
|
InitCheats();
|
|
automapping = 1;
|
|
|
|
gs = gs_defaults;
|
|
|
|
for (int i = 0; i < MAX_SW_PLAYERS; i++)
|
|
INITLIST(&Player[i].PanelSpriteList);
|
|
|
|
DebugOperate = true;
|
|
enginecompatibility_mode = ENGINECOMPATIBILITY_19961112;
|
|
|
|
if (SW_SHAREWARE)
|
|
Printf("SHADOW WARRIOR(tm) Version 1.2 (Shareware Version)\n");
|
|
else
|
|
Printf("SHADOW WARRIOR(tm) Version 1.2\n");
|
|
|
|
if (sw_snd_scratch == 0) // This is always 0 at this point - this check is only here to prevent whole program optimization from eliminating the variable.
|
|
Printf("Copyright (c) 1997 3D Realms Entertainment\n");
|
|
|
|
registerosdcommands();
|
|
|
|
numplayers = 1; myconnectindex = 0;
|
|
connecthead = 0; connectpoint2[0] = -1;
|
|
|
|
if (SW_SHAREWARE && numplayers > 4)
|
|
{
|
|
I_FatalError("To play a Network game with more than 4 players you must purchase "
|
|
"the full version. Read the Ordering Info screens for details.");
|
|
}
|
|
|
|
//Connect();
|
|
SortBreakInfo();
|
|
defineSky(DEFAULTPSKY, 1, nullptr);
|
|
|
|
memset(Track, 0, sizeof(Track));
|
|
memset(Player, 0, sizeof(Player));
|
|
for (int i = 0; i < MAX_SW_PLAYERS; i++)
|
|
INITLIST(&Player[i].PanelSpriteList);
|
|
|
|
LoadCustomInfoFromScript("engine/swcustom.txt"); // load the internal definitions. These also apply to the shareware version.
|
|
if (!SW_SHAREWARE)
|
|
LoadCustomInfoFromScript("swcustom.txt"); // Load user customisation information
|
|
|
|
SetTileNames();
|
|
userConfig.AddDefs.reset();
|
|
InitFX();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void GameInterface::DrawBackground(void)
|
|
{
|
|
const int TITLE_PIC = 2324;
|
|
twod->ClearScreen();
|
|
DrawTexture(twod, tileGetTexture(TITLE_PIC), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal,
|
|
DTA_Color, shadeToLight(20), TAG_DONE);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void InitLevelGlobals(void)
|
|
{
|
|
ChopTics = 0;
|
|
automapMode = am_off;
|
|
PlayerGravity = 24;
|
|
wait_active_check_offset = 0;
|
|
PlaxCeilGlobZadjust = PlaxFloorGlobZadjust = Z(500);
|
|
FinishedLevel = false;
|
|
AnimCnt = 0;
|
|
left_foot = false;
|
|
screenpeek = myconnectindex;
|
|
ClearInterpolations();
|
|
|
|
gNet.TimeLimitClock = gNet.TimeLimit;
|
|
|
|
|
|
for (auto& b : bosswasseen) b = false;
|
|
memset(BossSpriteNum,0,sizeof(BossSpriteNum));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// GLOBAL RESETS NOT DONE for LOAD GAME
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void InitLevelGlobals2(void)
|
|
{
|
|
InitTimingVars();
|
|
TotalKillable = 0;
|
|
Bunny_Count = 0;
|
|
FinishAnim = false;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void spawnactors(SpawnSpriteDef& sprites)
|
|
{
|
|
InitSpriteLists();
|
|
for (unsigned i = 0; i < sprites.sprites.Size(); i++)
|
|
{
|
|
if (sprites.sprites[i].statnum == MAXSTATUS)
|
|
{
|
|
continue;
|
|
}
|
|
auto sprt = &sprites.sprites[i];
|
|
auto actor = insertActor(sprt->sectp, sprt->statnum);
|
|
actor->spr = sprites.sprites[i];
|
|
actor->time = i;
|
|
if (sprites.sprext.Size()) actor->sprext = sprites.sprext[i];
|
|
else actor->sprext = {};
|
|
actor->spsmooth = {};
|
|
}
|
|
leveltimer = sprites.sprites.Size();
|
|
}
|
|
|
|
|
|
void InitLevel(MapRecord *maprec)
|
|
{
|
|
Terminate3DSounds();
|
|
|
|
// A few IMPORTANT GLOBAL RESETS
|
|
InitLevelGlobals();
|
|
|
|
Mus_Stop();
|
|
|
|
if (!maprec)
|
|
{
|
|
I_Error("Attempt to start game without level");
|
|
return;
|
|
}
|
|
InitLevelGlobals2();
|
|
|
|
if (NewGame)
|
|
{
|
|
for (int i = 0; i < MAX_SW_PLAYERS; i++)
|
|
{
|
|
// don't jack with the playerreadyflag
|
|
int ready_bak = Player[i].playerreadyflag;
|
|
int ver_bak = Player[i].PlayerVersion;
|
|
memset(&Player[i], 0, sizeof(Player[i]));
|
|
Player[i].playerreadyflag = ready_bak;
|
|
Player[i].PlayerVersion = ver_bak;
|
|
INITLIST(&Player[i].PanelSpriteList);
|
|
}
|
|
|
|
memset(puser, 0, sizeof(puser));
|
|
}
|
|
|
|
int16_t ang;
|
|
currentLevel = maprec;
|
|
int cursect;
|
|
SpawnSpriteDef sprites;
|
|
loadMap(maprec->fileName, SW_SHAREWARE ? 1 : 0, &Player[0].pos, &ang, &cursect, sprites);
|
|
spawnactors(sprites);
|
|
Player[0].cursector = §or[cursect];
|
|
|
|
SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name);
|
|
STAT_NewLevel(currentLevel->fileName);
|
|
TITLE_InformName(currentLevel->name);
|
|
Player[0].angle.ang = buildang(ang);
|
|
|
|
auto vissect = §or[0]; // hack alert!
|
|
if (vissect->extra != -1)
|
|
{
|
|
NormalVisibility = g_visibility = vissect->extra;
|
|
vissect->extra = 0;
|
|
}
|
|
else
|
|
NormalVisibility = g_visibility;
|
|
|
|
//
|
|
// Do Player stuff first
|
|
//
|
|
|
|
InitAllPlayers();
|
|
|
|
QueueReset();
|
|
PreMapCombineFloors();
|
|
InitMultiPlayerInfo();
|
|
InitAllPlayerSprites();
|
|
|
|
//
|
|
// Do setup for sprite, track, panel, sector, etc
|
|
//
|
|
|
|
// Set levels up
|
|
InitTimingVars();
|
|
|
|
SpriteSetup();
|
|
SpriteSetupPost(); // post processing - already gone once through the loop
|
|
InitLighting();
|
|
|
|
TrackSetup();
|
|
|
|
PlayerPanelSetup();
|
|
SectorSetup();
|
|
JS_InitMirrors();
|
|
|
|
PlaceSectorObjectsOnTracks();
|
|
PlaceActorsOnTracks();
|
|
PostSetupSectorObject();
|
|
SetupMirrorTiles();
|
|
CollectPortals();
|
|
|
|
// reset NewGame
|
|
NewGame = false;
|
|
setLevelStarted(maprec);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void InitRunLevel(void)
|
|
{
|
|
Mus_Stop();
|
|
|
|
DoTheCache();
|
|
|
|
// send packets with player info
|
|
InitNetPlayerOptions();
|
|
|
|
// Initialize Game part of network code
|
|
InitNetVars();
|
|
|
|
if (currentLevel)
|
|
{
|
|
PlaySong(currentLevel->music, currentLevel->cdSongId);
|
|
}
|
|
|
|
InitPrediction(&Player[myconnectindex]);
|
|
|
|
InitTimingVars();
|
|
|
|
if (snd_ambience)
|
|
StartAmbientSound();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void TerminateLevel(void)
|
|
{
|
|
videoFadePalette(0, 0, 0, 0);
|
|
if (!currentLevel) return;
|
|
|
|
int i, stat, pnum, ndx;
|
|
|
|
// Free any track points
|
|
for (ndx = 0; ndx < MAX_TRACKS; ndx++)
|
|
{
|
|
Track[ndx].FreeTrackPoints();
|
|
}
|
|
|
|
// Clear the tracks and other arrays holding pointers into the level data.
|
|
memset(Track, 0, sizeof(Track));
|
|
memset(SineWaveFloor, 0, sizeof(SineWaveFloor));
|
|
memset(SineWall, 0, sizeof(SineWall));
|
|
memset(SpringBoard, 0, sizeof(SpringBoard));
|
|
|
|
StopFX();
|
|
|
|
// Clear all anims and any memory associated with them
|
|
// Clear before killing sprites - save a little time
|
|
//AnimClear();
|
|
|
|
for (stat = STAT_PLAYER0; stat < STAT_PLAYER0 + numplayers; stat++)
|
|
{
|
|
|
|
pnum = stat - STAT_PLAYER0;
|
|
|
|
SWStatIterator it(stat);
|
|
if (auto actor = it.Next())
|
|
{
|
|
if (actor->hasU()) puser[pnum].CopyFromUser(actor);
|
|
}
|
|
}
|
|
|
|
// clear some pointers KillActor may operate upon.
|
|
SWSpriteIterator it;
|
|
while (auto actor = it.Next())
|
|
{
|
|
actor->user.targetActor = nullptr;
|
|
actor->user.flameActor = nullptr;
|
|
}
|
|
// Kill User memory and delete sprites
|
|
it.Reset();
|
|
while (auto actor = it.Next())
|
|
{
|
|
KillActor(actor);
|
|
}
|
|
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
PLAYER* pp = &Player[pnum];
|
|
|
|
// Free panel sprites for players
|
|
pClearSpriteList(pp);
|
|
|
|
// clear *all* pointers in Player!
|
|
pp->remote = {};
|
|
pp->sop = pp->sop_remote = nullptr;
|
|
pp->LadderSector = nullptr;
|
|
pp->cookieTime = 0;
|
|
pp->hi_sectp = pp->lo_sectp = nullptr;
|
|
pp->cursector = pp->lastcursector = pp->lv_sector = nullptr;
|
|
pp->sop_control = pp->sop_riding = nullptr;
|
|
pp->PanelSpriteList = {};
|
|
|
|
memset(pp->cookieQuote, 0, sizeof(pp->cookieQuote));
|
|
pp->DoPlayerAction = nullptr;
|
|
|
|
pp->actor = nullptr;
|
|
|
|
pp->PlayerUnderActor = nullptr;
|
|
|
|
memset(pp->HasKey, 0, sizeof(pp->HasKey));
|
|
|
|
//pp->WpnFlags = 0;
|
|
pp->CurWpn = nullptr;
|
|
|
|
memset(pp->Wpn, 0, sizeof(pp->Wpn));
|
|
memset(pp->InventoryTics, 0, sizeof(pp->InventoryTics));
|
|
|
|
pp->KillerActor = nullptr;;
|
|
|
|
INITLIST(&pp->PanelSpriteList);
|
|
}
|
|
}
|
|
|
|
|
|
static bool DidOrderSound;
|
|
static int zero = 0;
|
|
|
|
static void PlayOrderSound()
|
|
{
|
|
if (!DidOrderSound)
|
|
{
|
|
DidOrderSound = true;
|
|
int choose_snd = StdRandomRange(1000);
|
|
if (choose_snd > 500)
|
|
PlaySound(DIGI_WANGORDER1, v3df_dontpan, CHAN_BODY, CHANF_UI);
|
|
else
|
|
PlaySound(DIGI_WANGORDER2, v3df_dontpan, CHAN_BODY, CHANF_UI);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void GameInterface::LevelCompleted(MapRecord* map, int skill)
|
|
{
|
|
//ResetPalette(mpp);
|
|
COVER_SetReverb(0); // Reset reverb
|
|
Player[myconnectindex].Reverb = 0;
|
|
StopSound();
|
|
STAT_Update(map == nullptr);
|
|
|
|
SummaryInfo info{};
|
|
|
|
info.kills = Player[screenpeek].Kills;
|
|
info.maxkills = TotalKillable;
|
|
info.secrets = Player[screenpeek].SecretsFound;
|
|
info.maxsecrets = LevelSecrets;
|
|
info.time = PlayClock / 120;
|
|
|
|
ShowIntermission(currentLevel, map, &info, [=](bool)
|
|
{
|
|
if (map == nullptr)
|
|
{
|
|
FinishAnim = false;
|
|
PlaySong(ThemeSongs[0], ThemeTrack[0]);
|
|
if (isShareware())
|
|
{
|
|
PlayOrderSound();
|
|
gameaction = ga_creditsmenu;
|
|
}
|
|
else gameaction = ga_mainmenu;
|
|
}
|
|
else gameaction = ga_nextlevel;
|
|
});
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void GameInterface::NextLevel(MapRecord *map, int skill)
|
|
{
|
|
if (skill != -1) Skill = skill;
|
|
ShadowWarrior::NewGame = false;
|
|
InitLevel(map);
|
|
InitRunLevel();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void GameInterface::NewGame(MapRecord *map, int skill, bool)
|
|
{
|
|
if (skill != -1) Skill = skill;
|
|
ShadowWarrior::NewGame = true;
|
|
InitLevel(map);
|
|
InitRunLevel();
|
|
gameaction = ga_level;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int GameInterface::GetCurrentSkill()
|
|
{
|
|
return Skill;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void GameInterface::Ticker(void)
|
|
{
|
|
int i;
|
|
TRAVERSE_CONNECT(i)
|
|
{
|
|
auto pp = Player + i;
|
|
pp->lastinput = pp->input;
|
|
pp->input = playercmds[i].ucmd;
|
|
if (pp->lastinput.actions & SB_CENTERVIEW) pp->input.actions |= SB_CENTERVIEW;
|
|
}
|
|
|
|
domovethings();
|
|
r_NoInterpolate = paused;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void GameInterface::Render()
|
|
{
|
|
if (paused)
|
|
{
|
|
smoothratio = MaxSmoothRatio;
|
|
}
|
|
else
|
|
{
|
|
smoothratio = !cl_interpolate || cl_capfps ? MaxSmoothRatio : I_GetTimeFrac() * MaxSmoothRatio;
|
|
}
|
|
|
|
drawtime.Reset();
|
|
drawtime.Clock();
|
|
drawscreen(Player + screenpeek, smoothratio, false);
|
|
drawtime.Unclock();
|
|
}
|
|
|
|
|
|
void GameInterface::Startup()
|
|
{
|
|
PlayLogos(ga_mainmenunostopsound, ga_mainmenu, false);
|
|
}
|
|
|
|
|
|
void GameInterface::ErrorCleanup()
|
|
{
|
|
// Make sure we do not leave the game in an unstable state
|
|
TerminateLevel();
|
|
FinishAnim = false;
|
|
}
|
|
|
|
void GameInterface::ExitFromMenu()
|
|
{
|
|
endoomName = !isShareware() ? "swreg.bin" : "shadsw.bin";
|
|
ST_Endoom();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int RandomRange(int range)
|
|
{
|
|
uint32_t rand_num;
|
|
uint32_t value;
|
|
|
|
if (range <= 0)
|
|
return 0;
|
|
|
|
rand_num = RANDOM();
|
|
|
|
if (rand_num == 65535U)
|
|
rand_num--;
|
|
|
|
// shift values to give more precision
|
|
value = (rand_num << 14) / ((65535U << 14) / range);
|
|
|
|
if (value >= (uint32_t)range)
|
|
value = range - 1;
|
|
|
|
return value;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int StdRandomRange(int range)
|
|
{
|
|
uint32_t rand_num;
|
|
uint32_t value;
|
|
|
|
if (range <= 0)
|
|
return 0;
|
|
|
|
rand_num = rand();
|
|
|
|
if (rand_num == RAND_MAX)
|
|
rand_num--;
|
|
|
|
// shift values to give more precision
|
|
#if (RAND_MAX > 0x7fff)
|
|
value = rand_num / (((int)RAND_MAX) / range);
|
|
#else
|
|
value = (rand_num << 14) / ((((int)RAND_MAX) << 14) / range);
|
|
#endif
|
|
|
|
if (value >= (uint32_t)range)
|
|
value = range - 1;
|
|
|
|
return value;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
ReservedSpace GameInterface::GetReservedScreenSpace(int viewsize)
|
|
{
|
|
return { 0, 48 };
|
|
}
|
|
|
|
::GameInterface* CreateInterface()
|
|
{
|
|
return new GameInterface;
|
|
}
|
|
|
|
GameStats GameInterface::getStats()
|
|
{
|
|
PLAYER* pp = Player + myconnectindex;
|
|
return { pp->Kills, TotalKillable, pp->SecretsFound, LevelSecrets, PlayClock / 120, 0 };
|
|
}
|
|
|
|
void GameInterface::FreeLevelData()
|
|
{
|
|
TerminateLevel();
|
|
::GameInterface::FreeLevelData();
|
|
}
|
|
|
|
int GameInterface::Voxelize(int sprnum)
|
|
{
|
|
return (aVoxelArray[sprnum].Voxel);
|
|
}
|
|
|
|
END_SW_NS
|