mirror of
https://github.com/ZDoom/Raze.git
synced 2024-12-16 23:51:23 +00:00
Avoid passing this anywhere in the client code. It should only be set right before rendering the 3D view and the only code using the base palette should be the 3D renderer and hud_drawsprite. Also make the palette override CVARs 3D view only in debug mode.
3597 lines
91 KiB
C++
3597 lines
91 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"
|
|
// CTW NOTE
|
|
/*
|
|
Known remaining issues:
|
|
- Audio stuttering.
|
|
- CD Audio not looping properly (currently hard coded to restart about every 200 seconds.
|
|
- Hitting F5 to change resolution causes a crash (currently disabled).
|
|
- Multiplayer untested.
|
|
|
|
Things required to make savegames work:
|
|
- Load makesym.wpj and build it.
|
|
- In a DOS prompt, run "makesym sw.map swdata.map swcode.map"
|
|
- Copy swcode.map to swcode.sym and swdata.map to swdata.sym
|
|
*/
|
|
// CTW NOTE END
|
|
|
|
#define MAIN
|
|
#define QUIET
|
|
#include "build.h"
|
|
#include "baselayer.h"
|
|
|
|
#include "baselayer.h"
|
|
|
|
#include "names2.h"
|
|
#include "panel.h"
|
|
#include "game.h"
|
|
#include "interp.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 "mytypes.h"
|
|
|
|
#include "menus.h"
|
|
|
|
#include "gamecontrol.h"
|
|
#include "gamedefs.h"
|
|
|
|
#include "demo.h"
|
|
#include "misc.h"
|
|
//#include "exports.h"
|
|
|
|
#include "anim.h"
|
|
|
|
#include "misc.h"
|
|
#include "break.h"
|
|
#include "ninja.h"
|
|
#include "light.h"
|
|
#include "misc.h"
|
|
#include "jsector.h"
|
|
|
|
#include "common.h"
|
|
#include "gameconfigfile.h"
|
|
#include "printf.h"
|
|
#include "m_argv.h"
|
|
#include "debugbreak.h"
|
|
#include "menu.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 "osdcmds.h"
|
|
|
|
//#include "crc32.h"
|
|
|
|
CVAR(Bool, sw_ninjahack, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
|
CVAR(Bool, sw_darts, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
|
|
|
BEGIN_SW_NS
|
|
|
|
void pClearSpriteList(PLAYERp pp);
|
|
signed char MNU_InputSmallString(char*, short);
|
|
signed char MNU_InputString(char*, short);
|
|
SWBOOL IsCommand(const char* str);
|
|
SWBOOL MNU_StartNetGame(void);
|
|
extern SWBOOL mapcheat;
|
|
|
|
extern SWBOOL MultiPlayQuitFlag;
|
|
|
|
extern int sw_snd_scratch;
|
|
|
|
|
|
#if DEBUG
|
|
#define BETA 0
|
|
#endif
|
|
|
|
#define STAT_SCREEN_PIC 5114
|
|
#define TITLE_PIC 2324
|
|
#define THREED_REALMS_PIC 2325
|
|
#define TITLE_ROT_FLAGS (RS_TOPLEFT|ROTATE_SPRITE_SCREEN_CLIP|ROTATE_SPRITE_NON_MASK)
|
|
#define PAL_SIZE (256*3)
|
|
|
|
char DemoName[15][16];
|
|
|
|
// Stupid WallMart version!
|
|
//#define PLOCK_VERSION TRUE
|
|
|
|
#if PLOCK_VERSION
|
|
SWBOOL Global_PLock = TRUE;
|
|
#else
|
|
SWBOOL Global_PLock = FALSE;
|
|
#endif
|
|
|
|
int GameVersion = 20;
|
|
|
|
char DemoText[3][64];
|
|
int DemoTextYstart = 0;
|
|
|
|
int Follow_posx=0,Follow_posy=0;
|
|
|
|
SWBOOL NoMeters = FALSE;
|
|
short IntroAnimCount = 0;
|
|
short PlayingLevel = -1;
|
|
SWBOOL GraphicsMode = FALSE;
|
|
char CacheLastLevel[32] = "";
|
|
char PlayerNameArg[32] = "";
|
|
SWBOOL CleanExit = FALSE;
|
|
SWBOOL DemoModeMenuInit = FALSE;
|
|
SWBOOL FinishAnim = 0;
|
|
SWBOOL ShortGameMode = FALSE;
|
|
SWBOOL ReloadPrompt = FALSE;
|
|
SWBOOL NewGame = TRUE;
|
|
SWBOOL InMenuLevel = FALSE;
|
|
SWBOOL LoadGameOutsideMoveLoop = FALSE;
|
|
SWBOOL LoadGameFromDemo = FALSE;
|
|
extern SWBOOL NetBroadcastMode, NetModeOverride;
|
|
SWBOOL MultiPlayQuitFlag = FALSE;
|
|
//Miscellaneous variables
|
|
char MessageInputString[256];
|
|
char MessageOutputString[256];
|
|
SWBOOL ConInputMode = FALSE;
|
|
SWBOOL ConPanel = FALSE;
|
|
SWBOOL FinishedLevel = FALSE;
|
|
SWBOOL PanelUpdateMode = TRUE;
|
|
short HelpPage = 0;
|
|
short HelpPagePic[] = { 5115, 5116, 5117 };
|
|
SWBOOL InputMode = FALSE;
|
|
SWBOOL MessageInput = FALSE;
|
|
short screenpeek = 0;
|
|
SWBOOL NoDemoStartup = FALSE;
|
|
SWBOOL FirstTimeIntoGame;
|
|
|
|
SWBOOL PedanticMode;
|
|
|
|
SWBOOL LocationInfo = 0;
|
|
void drawoverheadmap(int cposx, int cposy, int czoom, short cang);
|
|
int DispFrameRate = FALSE;
|
|
int DispMono = TRUE;
|
|
int Fog = FALSE;
|
|
int FogColor;
|
|
SWBOOL PreCaching = TRUE;
|
|
int GodMode = FALSE;
|
|
SWBOOL BotMode = FALSE;
|
|
short Skill = 2;
|
|
short BetaVersion = 900;
|
|
short TotalKillable;
|
|
|
|
AUTO_NET Auto;
|
|
SWBOOL AutoNet = FALSE;
|
|
SWBOOL HasAutoColor = FALSE;
|
|
uint8_t AutoColor;
|
|
|
|
const GAME_SET gs_defaults =
|
|
{
|
|
2, // border
|
|
0, // border tile
|
|
// Network game settings
|
|
0, // GameType
|
|
0, // Level
|
|
0, // Monsters
|
|
FALSE, // HurtTeammate
|
|
TRUE, // SpawnMarkers Markers
|
|
FALSE, // TeamPlay
|
|
0, // Kill Limit
|
|
0, // Time Limit
|
|
0, // Color
|
|
TRUE, // nuke
|
|
};
|
|
GAME_SET gs;
|
|
|
|
SWBOOL PlayerTrackingMode = FALSE;
|
|
SWBOOL SlowMode = FALSE;
|
|
SWBOOL FrameAdvanceTics = 3;
|
|
SWBOOL ScrollMode2D = FALSE;
|
|
|
|
SWBOOL DebugSO = FALSE;
|
|
SWBOOL DebugPanel = FALSE;
|
|
SWBOOL DebugSector = FALSE;
|
|
SWBOOL DebugActor = FALSE;
|
|
SWBOOL DebugAnim = FALSE;
|
|
SWBOOL DebugOperate = FALSE;
|
|
SWBOOL DebugActorFreeze = FALSE;
|
|
void LoadingLevelScreen(void);
|
|
|
|
uint8_t FakeMultiNumPlayers;
|
|
|
|
int totalsynctics;
|
|
|
|
short Level = 0;
|
|
SWBOOL ExitLevel = FALSE;
|
|
int16_t OrigCommPlayers=0;
|
|
extern uint8_t CommPlayers;
|
|
extern SWBOOL CommEnabled;
|
|
extern int bufferjitter;
|
|
|
|
SWBOOL CameraTestMode = FALSE;
|
|
|
|
char ds[645]; // debug string
|
|
|
|
extern short NormalVisibility;
|
|
|
|
extern int quotebot, quotebotgoal; // Multiplayer typing buffer
|
|
char recbuf[80]; // Used as a temp buffer to hold typing text
|
|
|
|
#define ACT_STATUE 0
|
|
|
|
int score;
|
|
SWBOOL QuitFlag = FALSE;
|
|
SWBOOL InGame = FALSE;
|
|
|
|
SWBOOL CommandSetup = FALSE;
|
|
|
|
char UserMapName[80]="", buffer[80], ch;
|
|
char LevelName[20];
|
|
|
|
uint8_t DebugPrintColor = 255;
|
|
|
|
int krandcount;
|
|
|
|
/// L O C A L P R O T O T Y P E S /////////////////////////////////////////////////////////
|
|
void BOT_DeleteAllBots(void);
|
|
void BotPlayerInsert(PLAYERp pp);
|
|
void SybexScreen(void);
|
|
void PlayTheme(void);
|
|
void MenuLevel(void);
|
|
void StatScreen(PLAYERp mpp);
|
|
void InitRunLevel(void);
|
|
void RunLevel(void);
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static FILE *debug_fout = NULL;
|
|
|
|
void DebugWriteString(char *string)
|
|
{
|
|
|
|
#if BETA || !DEBUG
|
|
return;
|
|
#endif
|
|
|
|
if (!debug_fout)
|
|
{
|
|
if ((debug_fout = fopen("dbg.foo", "ab+")) == NULL)
|
|
return;
|
|
}
|
|
|
|
fprintf(debug_fout, "%s\n", string);
|
|
|
|
//fclose(debug_fout);
|
|
//debug_fout = NULL;
|
|
|
|
fflush(debug_fout);
|
|
}
|
|
|
|
void DebugWriteLoc(char *fname, int line)
|
|
{
|
|
|
|
#if BETA || !DEBUG
|
|
return;
|
|
#endif
|
|
|
|
if (!debug_fout)
|
|
{
|
|
if ((debug_fout = fopen("dbg.foo", "ab+")) == NULL)
|
|
return;
|
|
}
|
|
|
|
fprintf(debug_fout, "%s, %d\n", fname, line);
|
|
|
|
//fclose(debug_fout);
|
|
//debug_fout = NULL;
|
|
|
|
fflush(debug_fout);
|
|
}
|
|
|
|
void Mono_Print(char *str)
|
|
{
|
|
MONO_PRINT(str);
|
|
}
|
|
|
|
|
|
extern SWBOOL DrawScreen;
|
|
#if RANDOM_DEBUG
|
|
FILE *fout_err;
|
|
SWBOOL RandomPrint;
|
|
int krand1(char *file, unsigned line)
|
|
{
|
|
ASSERT(!DrawScreen);
|
|
if (RandomPrint && !Prediction)
|
|
{
|
|
extern uint32_t MoveThingsCount;
|
|
sprintf(ds,"mtc %d, %s, line %d, %d",MoveThingsCount,file,line,randomseed);
|
|
DebugWriteString(ds);
|
|
}
|
|
randomseed = ((randomseed * 21 + 1) & 65535);
|
|
return randomseed;
|
|
}
|
|
|
|
int krand2()
|
|
{
|
|
ASSERT(!DrawScreen);
|
|
randomseed = ((randomseed * 21 + 1) & 65535);
|
|
return randomseed;
|
|
}
|
|
|
|
#else
|
|
int krand1(void)
|
|
{
|
|
ASSERT(!DrawScreen);
|
|
krandcount++;
|
|
randomseed = ((randomseed * 21 + 1) & 65535);
|
|
return randomseed;
|
|
}
|
|
|
|
#endif
|
|
|
|
int PointOnLine(int x, int y, int x1, int y1, int x2, int y2)
|
|
{
|
|
// the closer to 0 the closer to the line the point is
|
|
return ((x2 - x1) * (y - y1)) - ((y2 - y1) * (x - x1));
|
|
}
|
|
|
|
int
|
|
Distance(int x1, int y1, int x2, int y2)
|
|
{
|
|
int min;
|
|
|
|
if ((x2 = x2 - x1) < 0)
|
|
x2 = -x2;
|
|
|
|
if ((y2 = y2 - y1) < 0)
|
|
y2 = -y2;
|
|
|
|
if (x2 > y2)
|
|
min = y2;
|
|
else
|
|
min = x2;
|
|
|
|
return x2 + y2 - DIV2(min);
|
|
}
|
|
|
|
void
|
|
setup2dscreen(void)
|
|
{
|
|
// qsetmode640350();
|
|
}
|
|
|
|
|
|
|
|
void TerminateGame(void)
|
|
{
|
|
DemoTerm();
|
|
|
|
ErrorCorrectionQuit();
|
|
|
|
// uninitmultiplayers();
|
|
|
|
if (CleanExit)
|
|
{
|
|
SybexScreen();
|
|
//TenScreen();
|
|
}
|
|
throw CExitEvent(3);
|
|
}
|
|
|
|
bool LoadLevel(const char *filename)
|
|
{
|
|
int16_t ang;
|
|
if (engineLoadBoard(filename, SW_SHAREWARE ? 1 : 0, (vec3_t *)&Player[0], &ang, &Player[0].cursectnum) == -1)
|
|
{
|
|
Printf("Level not found: %s", filename);
|
|
return false;
|
|
}
|
|
currentLevel = &mapList[Level];
|
|
SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name);
|
|
STAT_NewLevel(currentLevel->labelName);
|
|
Player[0].q16ang = fix16_from_int(ang);
|
|
return true;
|
|
}
|
|
|
|
void LoadDemoRun(void)
|
|
{
|
|
short i;
|
|
FILE *fin;
|
|
|
|
fin = fopen("demos.run","r");
|
|
if (fin)
|
|
{
|
|
memset(DemoName,'\0',sizeof(DemoName));
|
|
for (i = 0; i < ARRAY_SSIZE(DemoName); i++)
|
|
{
|
|
if (fscanf(fin, "%s", DemoName[i]) == EOF)
|
|
break;
|
|
}
|
|
if (i == ARRAY_SSIZE(DemoName))
|
|
Printf("WARNING: demos.run is too long, ignoring remaining files\n");
|
|
|
|
fclose(fin);
|
|
}
|
|
|
|
memset(DemoText,'\0',sizeof(DemoText));
|
|
fin = fopen("demotxt.run","r");
|
|
if (fin)
|
|
{
|
|
fgets(ds, 6, fin);
|
|
sscanf(ds,"%d",&DemoTextYstart);
|
|
for (i = 0; i < ARRAY_SSIZE(DemoText); i++)
|
|
{
|
|
if (fgets(DemoText[i], SIZ(DemoText[0])-1, fin) == NULL)
|
|
break;
|
|
}
|
|
if (i == ARRAY_SSIZE(DemoText))
|
|
Printf("WARNING: demotxt.run is too long, trimming the text\n");
|
|
|
|
fclose(fin);
|
|
}
|
|
}
|
|
|
|
void DisplayDemoText(void)
|
|
{
|
|
short w,h;
|
|
short i;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
MNU_MeasureString(DemoText[i], &w, &h);
|
|
PutStringTimer(Player, TEXT_TEST_COL(w), DemoTextYstart+(i*12), DemoText[i], 999);
|
|
}
|
|
}
|
|
|
|
void MultiSharewareCheck(void)
|
|
{
|
|
if (!SW_SHAREWARE) return;
|
|
if (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.");
|
|
}
|
|
}
|
|
|
|
|
|
// Some mem crap for Jim
|
|
// I reserve 1 meg of heap space for our use out side the cache
|
|
int TotalMemory = 0;
|
|
int ActualHeap = 0;
|
|
|
|
void InitAutoNet(void)
|
|
{
|
|
if (!AutoNet)
|
|
return;
|
|
|
|
gs.NetGameType = Auto.Rules;
|
|
gs.NetLevel = Auto.Level;
|
|
gs.NetMonsters = Auto.Enemy;
|
|
gs.NetSpawnMarkers = Auto.Markers;
|
|
gs.NetTeamPlay = Auto.Team;
|
|
gs.NetHurtTeammate = Auto.HurtTeam;
|
|
gs.NetKillLimit = Auto.Kill;
|
|
gs.NetTimeLimit = Auto.Time;
|
|
gs.NetColor = Auto.Color;
|
|
gs.NetNuke = Auto.Nuke;
|
|
}
|
|
|
|
|
|
void AnimateCacheCursor(void)
|
|
{
|
|
#if 0
|
|
struct rccoord old_pos;
|
|
static short cursor_num = 0;
|
|
static char cache_cursor[] = {'|','/','-','\\'};
|
|
|
|
if (GraphicsMode)
|
|
return;
|
|
|
|
cursor_num++;
|
|
if (cursor_num > 3)
|
|
cursor_num = 0;
|
|
|
|
//old_pos = _gettextposition();
|
|
//_settextposition( old_pos.row, old_pos.col );
|
|
//_settextposition( 24, 25);
|
|
_settextposition(25, 0);
|
|
sprintf(ds,"Loading sound and graphics %c", cache_cursor[cursor_num]);
|
|
_outtext(ds);
|
|
//_settextposition( old_pos.row, old_pos.col );
|
|
#endif
|
|
}
|
|
|
|
static int firstnet = 0; // JBF
|
|
|
|
typedef enum basepal_ {
|
|
BASEPAL = 0,
|
|
DREALMSPAL,
|
|
} basepal_t;
|
|
|
|
|
|
void SW_InitMultiPsky(void)
|
|
{
|
|
// default
|
|
psky_t* const defaultsky = tileSetupSky(DEFAULTPSKY);
|
|
defaultsky->lognumtiles = 1;
|
|
defaultsky->horizfrac = 8192;
|
|
}
|
|
|
|
bool InitGame()
|
|
{
|
|
extern int MovesPerPacket;
|
|
//void *ReserveMem=NULL;
|
|
int i;
|
|
|
|
DSPRINTF(ds,"InitGame...");
|
|
MONO_PRINT(ds);
|
|
|
|
engineInit();
|
|
|
|
InitAutoNet();
|
|
|
|
|
|
|
|
{
|
|
auto pal = fileSystem.LoadFile("3drealms.pal", 0);
|
|
if (pal.Size() >= 768)
|
|
{
|
|
for (auto& c : pal)
|
|
c <<= 2;
|
|
|
|
paletteSetColorTable(DREALMSPAL, pal.Data(), true, true);
|
|
}
|
|
}
|
|
|
|
|
|
timerInit(120);
|
|
|
|
InitPalette();
|
|
// sets numplayers, connecthead, connectpoint2, myconnectindex
|
|
|
|
#if 0
|
|
if (!firstnet)
|
|
initmultiplayers(0, NULL, 0, 0, 0);
|
|
else if (initmultiplayersparms(argc - firstnet, &argv[firstnet]))
|
|
{
|
|
Printf("Waiting for players...\n");
|
|
while (initmultiplayerscycle())
|
|
{
|
|
handleevents();
|
|
}
|
|
}
|
|
#else
|
|
numplayers = 1; myconnectindex = 0;
|
|
connecthead = 0; connectpoint2[0] = -1;
|
|
#endif
|
|
initsynccrc();
|
|
|
|
// code to duplicate packets
|
|
if (numplayers > 4 && MovesPerPacket == 1)
|
|
{
|
|
MovesPerPacket = 2;
|
|
}
|
|
|
|
MultiSharewareCheck();
|
|
|
|
if (numplayers > 1)
|
|
{
|
|
CommPlayers = numplayers;
|
|
OrigCommPlayers = CommPlayers;
|
|
CommEnabled = TRUE;
|
|
gNet.MultiGameType = MULTI_GAME_COMMBAT;
|
|
}
|
|
|
|
LoadDemoRun();
|
|
|
|
TileFiles.LoadArtSet("tiles%03d.art");
|
|
|
|
Connect();
|
|
SortBreakInfo();
|
|
parallaxtype = 1;
|
|
SW_InitMultiPsky();
|
|
|
|
memset(Track, 0, sizeof(Track));
|
|
|
|
memset(Player, 0, sizeof(Player));
|
|
for (i = 0; i < MAX_SW_PLAYERS; i++)
|
|
INITLIST(&Player[i].PanelSpriteList);
|
|
|
|
LoadKVXFromScript("swvoxfil.txt"); // Load voxels from script file
|
|
LoadPLockFromScript("swplock.txt"); // Get Parental Lock setup info
|
|
|
|
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
|
|
}
|
|
|
|
if (!loaddefinitionsfile(G_DefFile())) Printf("Definitions file loaded.\n");
|
|
|
|
userConfig.AddDefs.reset();
|
|
|
|
enginePostInit();
|
|
|
|
videoInit();
|
|
|
|
DemoModeMenuInit = TRUE;
|
|
// precache as much stuff as you can
|
|
if (UserMapName[0] == '\0')
|
|
{
|
|
AnimateCacheCursor();
|
|
if (!LoadLevel("$dozer.map")) return false;
|
|
AnimateCacheCursor();
|
|
SetupPreCache();
|
|
DoTheCache();
|
|
}
|
|
else
|
|
{
|
|
AnimateCacheCursor();
|
|
if (!LoadLevel(UserMapName)) return false;
|
|
AnimateCacheCursor();
|
|
SetupPreCache();
|
|
DoTheCache();
|
|
}
|
|
|
|
GraphicsMode = TRUE;
|
|
|
|
InitFX(); // JBF: do it down here so we get a hold of the window handle
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
Directory of C:\DEV\SW\MIDI
|
|
EXECUT11 MID
|
|
HROSHMA6 MID
|
|
HOSHIA02 MID
|
|
INTRO131 MID
|
|
KOTEC2 MID
|
|
KOTOKI12 MID
|
|
NIPPON34 MID
|
|
NOKI41 MID
|
|
SANAI MID
|
|
SIANRA23 MID
|
|
TKYO2007 MID
|
|
TYTAIK16 MID
|
|
YOKOHA03 MID
|
|
*/
|
|
|
|
short SongLevelNum;
|
|
|
|
FString ThemeSongs[6];
|
|
int ThemeTrack[6];
|
|
|
|
void InitNewGame(void)
|
|
{
|
|
int i, ready_bak;
|
|
int ver_bak;
|
|
|
|
//waitforeverybody(); // since ready flag resets after this point, need to carefully sync
|
|
|
|
for (i = 0; i < MAX_SW_PLAYERS; i++)
|
|
{
|
|
// don't jack with the playerreadyflag
|
|
ready_bak = Player[i].playerreadyflag;
|
|
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));
|
|
}
|
|
|
|
void FindLevelInfo(char *map_name, short *level)
|
|
{
|
|
short j;
|
|
|
|
for (j = 1; j <= MAX_LEVELS; j++)
|
|
{
|
|
if (Bstrcasecmp(map_name, mapList[j].fileName.GetChars()) == 0)
|
|
{
|
|
*level = j;
|
|
return;
|
|
}
|
|
}
|
|
|
|
*level = 0;
|
|
return;
|
|
}
|
|
|
|
int ChopTics;
|
|
void InitLevelGlobals(void)
|
|
{
|
|
extern char PlayerGravity;
|
|
extern short wait_active_check_offset;
|
|
//extern short Zombies;
|
|
extern int PlaxCeilGlobZadjust, PlaxFloorGlobZadjust;
|
|
extern SWBOOL left_foot;
|
|
extern SWBOOL serpwasseen;
|
|
extern SWBOOL sumowasseen;
|
|
extern SWBOOL zillawasseen;
|
|
extern short BossSpriteNum[3];
|
|
|
|
ChopTics = 0;
|
|
dimensionmode = 3;
|
|
zoom = 768;
|
|
PlayerGravity = 24;
|
|
wait_active_check_offset = 0;
|
|
PlaxCeilGlobZadjust = PlaxFloorGlobZadjust = Z(500);
|
|
FinishedLevel = FALSE;
|
|
AnimCnt = 0;
|
|
left_foot = FALSE;
|
|
screenpeek = myconnectindex;
|
|
numinterpolations = short_numinterpolations = 0;
|
|
|
|
gNet.TimeLimitClock = gNet.TimeLimit;
|
|
|
|
serpwasseen = FALSE;
|
|
sumowasseen = FALSE;
|
|
zillawasseen = FALSE;
|
|
memset(BossSpriteNum,-1,sizeof(BossSpriteNum));
|
|
|
|
PedanticMode = (DemoPlaying || DemoRecording || DemoEdit || DemoMode);
|
|
}
|
|
|
|
void InitLevelGlobals2(void)
|
|
{
|
|
extern short Bunny_Count;
|
|
// GLOBAL RESETS NOT DONE for LOAD GAME
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
InitTimingVars();
|
|
TotalKillable = 0;
|
|
Bunny_Count = 0;
|
|
FinishAnim = 0;
|
|
}
|
|
|
|
void
|
|
InitLevel(void)
|
|
{
|
|
if (LoadGameOutsideMoveLoop)
|
|
{
|
|
InitLevelGlobals();
|
|
return;
|
|
}
|
|
|
|
static int DemoNumber = 0;
|
|
|
|
Terminate3DSounds();
|
|
|
|
// A few IMPORTANT GLOBAL RESETS
|
|
InitLevelGlobals();
|
|
|
|
if (!DemoMode)
|
|
Mus_Stop();
|
|
|
|
InitLevelGlobals2();
|
|
if (DemoMode)
|
|
{
|
|
Level = 0;
|
|
NewGame = TRUE;
|
|
DemoInitOnce = FALSE;
|
|
strcpy(DemoFileName, DemoName[DemoNumber]);
|
|
DemoNumber++;
|
|
if (!DemoName[DemoNumber][0])
|
|
DemoNumber = 0;
|
|
|
|
// read header and such
|
|
DemoPlaySetup();
|
|
|
|
strcpy(LevelName, DemoLevelName);
|
|
|
|
FindLevelInfo(LevelName, &Level);
|
|
if (Level > 0)
|
|
{
|
|
strcpy(LevelName, mapList[Level].fileName);
|
|
UserMapName[0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
strcpy(UserMapName, DemoLevelName);
|
|
Level = 0;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (Level < 0)
|
|
Level = 0;
|
|
|
|
if (Level > MAX_LEVELS)
|
|
Level = 1;
|
|
|
|
// extra code in case something is resetting these values
|
|
if (NewGame)
|
|
{
|
|
//Level = 1;
|
|
//DemoPlaying = FALSE;
|
|
DemoMode = FALSE;
|
|
//DemoRecording = FALSE;
|
|
//DemoEdit = FALSE;
|
|
}
|
|
|
|
if (UserMapName[0])
|
|
{
|
|
strcpy(LevelName, UserMapName);
|
|
|
|
Level = 0;
|
|
FindLevelInfo(UserMapName, &Level);
|
|
|
|
if (Level > 0)
|
|
{
|
|
// user map is part of game - treat it as such
|
|
strcpy(LevelName, mapList[Level].fileName);
|
|
UserMapName[0] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(LevelName, mapList[Level].fileName);
|
|
}
|
|
}
|
|
|
|
PlayingLevel = Level;
|
|
|
|
if (NewGame)
|
|
InitNewGame();
|
|
|
|
LoadingLevelScreen();
|
|
MONO_PRINT("LoadintLevelScreen");
|
|
if (!DemoMode && !DemoInitOnce)
|
|
DemoPlaySetup();
|
|
|
|
if (!LoadLevel(LevelName))
|
|
{
|
|
NewGame = false;
|
|
return;
|
|
}
|
|
STAT_NewLevel(LevelName);
|
|
|
|
if (Bstrcasecmp(CacheLastLevel, LevelName) != 0)
|
|
// clears gotpic and does some bit setting
|
|
SetupPreCache();
|
|
else
|
|
memset(gotpic,0,sizeof(gotpic));
|
|
|
|
if (sector[0].extra != -1)
|
|
{
|
|
NormalVisibility = g_visibility = sector[0].extra;
|
|
sector[0].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();
|
|
JS_InitLockouts(); // Setup the lockout linked lists
|
|
JS_ToggleLockouts(); // Init lockouts on/off
|
|
|
|
PlaceSectorObjectsOnTracks();
|
|
PlaceActorsOnTracks();
|
|
PostSetupSectorObject();
|
|
SetupMirrorTiles();
|
|
initlava();
|
|
|
|
SongLevelNum = Level;
|
|
|
|
if (DemoMode)
|
|
{
|
|
DisplayDemoText();
|
|
}
|
|
|
|
// reset NewGame
|
|
NewGame = FALSE;
|
|
|
|
DSPRINTF(ds,"End of InitLevel...");
|
|
MONO_PRINT(ds);
|
|
|
|
#if 0
|
|
#if DEBUG
|
|
if (!cansee(43594, -92986, 0x3fffffff, 290,
|
|
43180, -91707, 0x3fffffff, 290))
|
|
{
|
|
DSPRINTF(ds,"cansee failed");
|
|
MONO_PRINT(ds);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void
|
|
TerminateLevel(void)
|
|
{
|
|
int i, nexti, stat, pnum, ndx;
|
|
SECT_USERp *sectu;
|
|
|
|
//HEAP_CHECK();
|
|
|
|
DemoTerm();
|
|
|
|
// Free any track points
|
|
for (ndx = 0; ndx < MAX_TRACKS; ndx++)
|
|
{
|
|
if (Track[ndx].TrackPoint)
|
|
{
|
|
FreeMem(Track[ndx].TrackPoint);
|
|
// !JIM! I added null assigner
|
|
Track[ndx].TrackPoint = NULL;
|
|
}
|
|
}
|
|
|
|
// Clear the tracks
|
|
memset(Track, 0, sizeof(Track));
|
|
|
|
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;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[stat], i, nexti)
|
|
{
|
|
if (User[i])
|
|
memcpy(&puser[pnum], User[i], sizeof(USER));
|
|
}
|
|
}
|
|
|
|
// Kill User memory and delete sprites
|
|
// for (stat = 0; stat < STAT_ALL; stat++)
|
|
for (stat = 0; stat < MAXSTATUS; stat++)
|
|
{
|
|
TRAVERSE_SPRITE_STAT(headspritestat[stat], i, nexti)
|
|
{
|
|
KillSprite(i);
|
|
}
|
|
}
|
|
|
|
// Free SectUser memory
|
|
for (sectu = &SectUser[0];
|
|
sectu < &SectUser[MAXSECTORS];
|
|
sectu++)
|
|
{
|
|
if (*sectu)
|
|
{
|
|
////DSPRINTF(ds,"Sect User Free %d",sectu-SectUser);
|
|
//MONO_PRINT(ds);
|
|
FreeMem(*sectu);
|
|
*sectu = NULL;
|
|
}
|
|
}
|
|
|
|
//memset(&User[0], 0, sizeof(User));
|
|
memset(&SectUser[0], 0, sizeof(SectUser));
|
|
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
PLAYERp pp = Player + pnum;
|
|
|
|
// Free panel sprites for players
|
|
pClearSpriteList(pp);
|
|
|
|
pp->DoPlayerAction = NULL;
|
|
|
|
pp->SpriteP = NULL;
|
|
pp->PlayerSprite = -1;
|
|
|
|
pp->UnderSpriteP = NULL;
|
|
pp->PlayerUnderSprite = -1;
|
|
|
|
memset(pp->HasKey, 0, sizeof(pp->HasKey));
|
|
|
|
//pp->WpnFlags = 0;
|
|
pp->CurWpn = NULL;
|
|
|
|
memset(pp->Wpn, 0, sizeof(pp->Wpn));
|
|
memset(pp->InventoryTics, 0, sizeof(pp->InventoryTics));
|
|
|
|
pp->Killer = -1;
|
|
|
|
INITLIST(&pp->PanelSpriteList);
|
|
}
|
|
|
|
JS_UnInitLockouts();
|
|
|
|
//HEAP_CHECK();
|
|
}
|
|
|
|
void NewLevel(void)
|
|
{
|
|
if (DemoPlaying)
|
|
{
|
|
InitLevel();
|
|
InitRunLevel();
|
|
|
|
DemoInitOnce = FALSE;
|
|
if (DemoMode)
|
|
{
|
|
if (DemoModeMenuInit)
|
|
{
|
|
DemoModeMenuInit = FALSE;
|
|
inputState.ClearKeyStatus(sc_Escape);
|
|
}
|
|
}
|
|
|
|
DemoPlayBack();
|
|
|
|
if (DemoRecording && DemoEdit)
|
|
{
|
|
RunLevel();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
InitLevel();
|
|
RunLevel();
|
|
}
|
|
while (LoadGameOutsideMoveLoop);
|
|
STAT_Update(false);
|
|
|
|
if (!QuitFlag)
|
|
{
|
|
// for good measure do this
|
|
ready2send = 0;
|
|
waitforeverybody();
|
|
}
|
|
|
|
StatScreen(&Player[myconnectindex]);
|
|
}
|
|
|
|
if (LoadGameFromDemo)
|
|
LoadGameFromDemo = FALSE;
|
|
else
|
|
TerminateLevel();
|
|
|
|
InGame = FALSE;
|
|
|
|
if (SW_SHAREWARE)
|
|
{
|
|
if (FinishAnim)
|
|
{
|
|
PlayTheme();
|
|
MenuLevel();
|
|
STAT_Update(true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FinishAnim == ANIM_ZILLA || FinishAnim == ANIM_SERP)
|
|
{
|
|
PlayTheme();
|
|
MenuLevel();
|
|
STAT_Update(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
uint8_t* KeyPressedRange(uint8_t* kb, uint8_t* ke)
|
|
{
|
|
uint8_t* k;
|
|
|
|
for (k = kb; k <= ke; k++)
|
|
{
|
|
if (*k)
|
|
return k;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void ResetKeyRange(uint8_t* kb, uint8_t* ke)
|
|
{
|
|
uint8_t* k;
|
|
|
|
for (k = kb; k <= ke; k++)
|
|
{
|
|
*k = 0;
|
|
}
|
|
}
|
|
|
|
void PlayTheme()
|
|
{
|
|
// start music at logo
|
|
PlaySong(nullptr, ThemeSongs[0], ThemeTrack[0]);
|
|
|
|
DSPRINTF(ds,"After music stuff...");
|
|
MONO_PRINT(ds);
|
|
}
|
|
|
|
void LogoLevel(void)
|
|
{
|
|
int fin;
|
|
|
|
if (userConfig.nologo) return;
|
|
DSPRINTF(ds,"LogoLevel...");
|
|
MONO_PRINT(ds);
|
|
|
|
MONO_PRINT(ds);
|
|
|
|
//FadeOut(0, 0);
|
|
ready2send = 0;
|
|
totalclock = 0;
|
|
ototalclock = 0;
|
|
|
|
DSPRINTF(ds,"About to display 3drealms pic...");
|
|
MONO_PRINT(ds);
|
|
|
|
//FadeIn(0, 3);
|
|
|
|
inputState.ClearAllInput();
|
|
while (TRUE)
|
|
{
|
|
twod->ClearScreen();
|
|
rotatesprite(0, 0, RS_SCALE, 0, THREED_REALMS_PIC, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1, nullptr, DREALMSPAL);
|
|
videoNextPage();
|
|
|
|
handleevents();
|
|
|
|
// limits checks to max of 40 times a second
|
|
if (totalclock >= ototalclock + synctics)
|
|
{
|
|
ototalclock += synctics;
|
|
}
|
|
|
|
if (totalclock > 5*120 || inputState.CheckAllInput())
|
|
{
|
|
inputState.ClearAllInput();
|
|
break;
|
|
}
|
|
}
|
|
|
|
twod->ClearScreen();
|
|
videoNextPage();
|
|
|
|
// put up a blank screen while loading
|
|
|
|
DSPRINTF(ds,"End of LogoLevel...");
|
|
MONO_PRINT(ds);
|
|
|
|
}
|
|
|
|
void CreditsLevel(void)
|
|
{
|
|
int curpic;
|
|
int handle;
|
|
uint32_t timer = 0;
|
|
int zero=0;
|
|
short save;
|
|
#define CREDITS1_PIC 5111
|
|
#define CREDITS2_PIC 5118
|
|
|
|
twod->ClearScreen();
|
|
videoNextPage();
|
|
inputState.ClearAllInput();
|
|
|
|
// Lo Wang feel like singing!
|
|
PlaySound(DIGI_JG95012, v3df_none, CHAN_VOICE, CHANF_UI);
|
|
while (soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr, CHAN_VOICE))
|
|
{
|
|
DoUpdateSounds();
|
|
handleevents();
|
|
if (inputState.CheckAllInput())
|
|
break;
|
|
videoNextPage();
|
|
}
|
|
StopSound();
|
|
|
|
// try 14 then 2 then quit
|
|
if (!PlaySong(nullptr, ThemeSongs[5], ThemeTrack[5], true))
|
|
{
|
|
PlaySong(nullptr, nullptr, 2, true);
|
|
}
|
|
|
|
ready2send = 0;
|
|
totalclock = 0;
|
|
ototalclock = 0;
|
|
|
|
inputState.ClearAllInput();
|
|
curpic = CREDITS1_PIC;
|
|
|
|
while (!inputState.CheckAllInput())
|
|
{
|
|
handleevents();
|
|
|
|
// limits checks to max of 40 times a second
|
|
if (totalclock >= ototalclock + synctics)
|
|
{
|
|
ototalclock += synctics;
|
|
timer += synctics;
|
|
}
|
|
|
|
rotatesprite(0, 0, RS_SCALE, 0, curpic, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
|
|
videoNextPage();
|
|
|
|
if (timer > 8*120)
|
|
{
|
|
curpic = CREDITS2_PIC;
|
|
}
|
|
|
|
if (timer > 16*120)
|
|
{
|
|
timer = 0;
|
|
curpic = CREDITS1_PIC;
|
|
}
|
|
handleevents();
|
|
}
|
|
|
|
// put up a blank screen while loading
|
|
twod->ClearScreen();
|
|
videoNextPage();
|
|
inputState.ClearAllInput();
|
|
Mus_Stop();
|
|
}
|
|
|
|
|
|
void SybexScreen(void)
|
|
{
|
|
if (!SW_SHAREWARE) return;
|
|
|
|
if (CommEnabled)
|
|
return;
|
|
|
|
rotatesprite(0, 0, RS_SCALE, 0, 5261, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
videoNextPage();
|
|
|
|
inputState.ClearAllInput();
|
|
while (!inputState.CheckAllInput()) handleevents();
|
|
}
|
|
|
|
// CTW REMOVED END
|
|
|
|
void DrawMenuLevelScreen(void)
|
|
{
|
|
twod->ClearScreen();
|
|
rotatesprite(0, 0, RS_SCALE, 0, TITLE_PIC, 20, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
}
|
|
|
|
void DrawStatScreen(void)
|
|
{
|
|
twod->ClearScreen();
|
|
rotatesprite(0, 0, RS_SCALE, 0, STAT_SCREEN_PIC, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
}
|
|
|
|
void DrawLoadLevelScreen(void)
|
|
{
|
|
twod->ClearScreen();
|
|
rotatesprite(0, 0, RS_SCALE, 0, TITLE_PIC, 20, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
}
|
|
|
|
short PlayerQuitMenuLevel = -1;
|
|
|
|
void IntroAnimLevel(void)
|
|
{
|
|
if (userConfig.nologo) return;
|
|
DSPRINTF(ds,"IntroAnimLevel");
|
|
MONO_PRINT(ds);
|
|
playanm(0);
|
|
}
|
|
|
|
void MenuLevel(void)
|
|
{
|
|
short w,h;
|
|
|
|
M_StartControlPanel(false);
|
|
M_SetMenu(NAME_Mainmenu);
|
|
// do demos only if not playing multi play
|
|
if (!CommEnabled && numplayers <= 1 && !FinishAnim && !NoDemoStartup)
|
|
{
|
|
// demos exist - do demo instead
|
|
if (DemoName[0][0] != '\0')
|
|
{
|
|
DemoMode = TRUE;
|
|
DemoPlaying = TRUE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
DemoMode = FALSE;
|
|
DemoPlaying = FALSE;
|
|
|
|
twod->ClearScreen();
|
|
videoNextPage();
|
|
|
|
//FadeOut(0, 0);
|
|
ready2send = 0;
|
|
totalclock = 0;
|
|
ototalclock = 0;
|
|
ExitLevel = FALSE;
|
|
InMenuLevel = TRUE;
|
|
|
|
DrawMenuLevelScreen();
|
|
|
|
if (CommEnabled)
|
|
{
|
|
sprintf(ds,"Lo Wang is waiting for other players...");
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 170, ds, 1, 16);
|
|
|
|
sprintf(ds,"They are afraid!");
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 180, ds, 1, 16);
|
|
}
|
|
|
|
videoNextPage();
|
|
//FadeIn(0, 3);
|
|
|
|
waitforeverybody();
|
|
|
|
inputState.ClearAllInput();
|
|
|
|
if (SW_SHAREWARE)
|
|
{
|
|
// go to ordering menu only if shareware
|
|
if (FinishAnim)
|
|
{
|
|
inputState.ClearKeyStatus(sc_Escape);
|
|
M_StartControlPanel(false);
|
|
M_SetMenu(NAME_CreditsMenu);
|
|
FinishAnim = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FinishAnim = 0;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
handleevents();
|
|
D_ProcessEvents();
|
|
C_RunDelayedCommands();
|
|
|
|
// limits checks to max of 40 times a second
|
|
if (totalclock >= ototalclock + synctics)
|
|
{
|
|
ototalclock += synctics;
|
|
if (CommEnabled)
|
|
getpackets();
|
|
}
|
|
|
|
if (CommEnabled)
|
|
{
|
|
if (MultiPlayQuitFlag)
|
|
{
|
|
uint8_t pbuf[1];
|
|
QuitFlag = TRUE;
|
|
pbuf[0] = PACKET_TYPE_MENU_LEVEL_QUIT;
|
|
netbroadcastpacket(pbuf, 1); // TENSW
|
|
break;
|
|
}
|
|
|
|
if (PlayerQuitMenuLevel >= 0)
|
|
{
|
|
MenuCommPlayerQuit(PlayerQuitMenuLevel);
|
|
PlayerQuitMenuLevel = -1;
|
|
}
|
|
}
|
|
|
|
if (ExitLevel)
|
|
{
|
|
// Quiting Level
|
|
ExitLevel = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (QuitFlag)
|
|
{
|
|
// Quiting Game
|
|
break;
|
|
}
|
|
|
|
// must lock the clock for drawing so animations will happen
|
|
totalclocklock = totalclock;
|
|
|
|
//drawscreen as fast as you can
|
|
DrawMenuLevelScreen();
|
|
DoUpdateSounds();
|
|
|
|
videoNextPage();
|
|
}
|
|
|
|
inputState.ClearAllInput();
|
|
M_ClearMenus();
|
|
InMenuLevel = FALSE;
|
|
twod->ClearScreen();
|
|
videoNextPage();
|
|
}
|
|
|
|
void
|
|
LoadingLevelScreen(void)
|
|
{
|
|
short w,h;
|
|
extern SWBOOL DemoMode;
|
|
DrawLoadLevelScreen();
|
|
|
|
if (DemoMode)
|
|
sprintf(ds,"DEMO");
|
|
else
|
|
sprintf(ds,"ENTERING");
|
|
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 170, ds,1,16);
|
|
|
|
auto ds = currentLevel->DisplayName();
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 180, ds,1,16);
|
|
|
|
videoNextPage();
|
|
}
|
|
|
|
void gNextState(STATEp *State)
|
|
{
|
|
// Transition to the next state
|
|
*State = (*State)->NextState;
|
|
|
|
if (TEST((*State)->Tics, SF_QUICK_CALL))
|
|
{
|
|
(*(*State)->Animator)(0);
|
|
*State = (*State)->NextState;
|
|
}
|
|
}
|
|
|
|
// Generic state control
|
|
void gStateControl(STATEp *State, int *tics)
|
|
{
|
|
*tics += synctics;
|
|
|
|
// Skip states if too much time has passed
|
|
while (*tics >= (*State)->Tics)
|
|
{
|
|
// Set Tics
|
|
*tics -= (*State)->Tics;
|
|
gNextState(State);
|
|
}
|
|
|
|
// Call the correct animator
|
|
if ((*State)->Animator)
|
|
(*(*State)->Animator)(0);
|
|
}
|
|
|
|
int BonusPunchSound(short UNUSED(SpriteNum))
|
|
{
|
|
PLAYERp pp = Player + myconnectindex;
|
|
PlaySound(DIGI_PLAYERYELL3, pp, v3df_none);
|
|
return 0;
|
|
}
|
|
|
|
int BonusKickSound(short UNUSED(SpriteNum))
|
|
{
|
|
PLAYERp pp = Player + myconnectindex;
|
|
PlaySound(DIGI_PLAYERYELL2, pp, v3df_none);
|
|
return 0;
|
|
}
|
|
|
|
int BonusGrabSound(short UNUSED(SpriteNum))
|
|
{
|
|
PLAYERp pp = Player + myconnectindex;
|
|
PlaySound(DIGI_BONUS_GRAB, pp, v3df_none);
|
|
return 0;
|
|
}
|
|
|
|
extern SWBOOL FinishedLevel;
|
|
extern int PlayClock;
|
|
extern short LevelSecrets;
|
|
extern short TotalKillable;
|
|
|
|
void BonusScreen()
|
|
{
|
|
int minutes,seconds,second_tics;
|
|
|
|
short w,h;
|
|
short limit;
|
|
|
|
|
|
#define BONUS_SCREEN_PIC 5120
|
|
#define BONUS_ANIM 5121
|
|
#define BONUS_ANIM_FRAMES (5159-5121)
|
|
|
|
#define BREAK_LIGHT_RATE 18
|
|
|
|
#define BONUS_PUNCH 5121
|
|
#define BONUS_KICK 5136
|
|
#define BONUS_GRAB 5151
|
|
#define BONUS_REST 5121
|
|
|
|
#define BONUS_TICS 8
|
|
#define BONUS_GRAB_TICS 20
|
|
#define BONUS_REST_TICS 50
|
|
|
|
static STATE s_BonusPunch[] =
|
|
{
|
|
{BONUS_PUNCH + 0, BONUS_TICS, NULL, &s_BonusPunch[1]},
|
|
{BONUS_PUNCH + 1, BONUS_TICS, NULL, &s_BonusPunch[2]},
|
|
{BONUS_PUNCH + 2, BONUS_TICS, NULL, &s_BonusPunch[3]},
|
|
{BONUS_PUNCH + 2, 0|SF_QUICK_CALL, BonusPunchSound, &s_BonusPunch[4]},
|
|
{BONUS_PUNCH + 3, BONUS_TICS, NULL, &s_BonusPunch[5]},
|
|
{BONUS_PUNCH + 4, BONUS_TICS, NULL, &s_BonusPunch[6]},
|
|
{BONUS_PUNCH + 5, BONUS_TICS, NULL, &s_BonusPunch[7]},
|
|
{BONUS_PUNCH + 6, BONUS_TICS, NULL, &s_BonusPunch[8]},
|
|
{BONUS_PUNCH + 7, BONUS_TICS, NULL, &s_BonusPunch[9]},
|
|
{BONUS_PUNCH + 8, BONUS_TICS, NULL, &s_BonusPunch[10]},
|
|
{BONUS_PUNCH + 9, BONUS_TICS, NULL, &s_BonusPunch[11]},
|
|
{BONUS_PUNCH + 10, BONUS_TICS, NULL, &s_BonusPunch[12]},
|
|
{BONUS_PUNCH + 11, BONUS_TICS, NULL, &s_BonusPunch[13]},
|
|
{BONUS_PUNCH + 12, BONUS_TICS, NULL, &s_BonusPunch[14]},
|
|
{BONUS_PUNCH + 14, 90, NULL, &s_BonusPunch[15]},
|
|
{BONUS_PUNCH + 14, BONUS_TICS, NULL, &s_BonusPunch[15]},
|
|
};
|
|
|
|
static STATE s_BonusKick[] =
|
|
{
|
|
{BONUS_KICK + 0, BONUS_TICS, NULL, &s_BonusKick[1]},
|
|
{BONUS_KICK + 1, BONUS_TICS, NULL, &s_BonusKick[2]},
|
|
{BONUS_KICK + 2, BONUS_TICS, NULL, &s_BonusKick[3]},
|
|
{BONUS_KICK + 2, 0|SF_QUICK_CALL, BonusKickSound, &s_BonusKick[4]},
|
|
{BONUS_KICK + 3, BONUS_TICS, NULL, &s_BonusKick[5]},
|
|
{BONUS_KICK + 4, BONUS_TICS, NULL, &s_BonusKick[6]},
|
|
{BONUS_KICK + 5, BONUS_TICS, NULL, &s_BonusKick[7]},
|
|
{BONUS_KICK + 6, BONUS_TICS, NULL, &s_BonusKick[8]},
|
|
{BONUS_KICK + 7, BONUS_TICS, NULL, &s_BonusKick[9]},
|
|
{BONUS_KICK + 8, BONUS_TICS, NULL, &s_BonusKick[10]},
|
|
{BONUS_KICK + 9, BONUS_TICS, NULL, &s_BonusKick[11]},
|
|
{BONUS_KICK + 10, BONUS_TICS, NULL, &s_BonusKick[12]},
|
|
{BONUS_KICK + 11, BONUS_TICS, NULL, &s_BonusKick[13]},
|
|
{BONUS_KICK + 12, BONUS_TICS, NULL, &s_BonusKick[14]},
|
|
{BONUS_KICK + 14, 90, NULL, &s_BonusKick[15]},
|
|
{BONUS_KICK + 14, BONUS_TICS, NULL, &s_BonusKick[15]},
|
|
};
|
|
|
|
static STATE s_BonusGrab[] =
|
|
{
|
|
{BONUS_GRAB + 0, BONUS_GRAB_TICS, NULL, &s_BonusGrab[1]},
|
|
{BONUS_GRAB + 1, BONUS_GRAB_TICS, NULL, &s_BonusGrab[2]},
|
|
{BONUS_GRAB + 2, BONUS_GRAB_TICS, NULL, &s_BonusGrab[3]},
|
|
{BONUS_GRAB + 2, 0|SF_QUICK_CALL, BonusGrabSound, &s_BonusGrab[4]},
|
|
{BONUS_GRAB + 3, BONUS_GRAB_TICS, NULL, &s_BonusGrab[5]},
|
|
{BONUS_GRAB + 4, BONUS_GRAB_TICS, NULL, &s_BonusGrab[6]},
|
|
{BONUS_GRAB + 5, BONUS_GRAB_TICS, NULL, &s_BonusGrab[7]},
|
|
{BONUS_GRAB + 6, BONUS_GRAB_TICS, NULL, &s_BonusGrab[8]},
|
|
{BONUS_GRAB + 7, BONUS_GRAB_TICS, NULL, &s_BonusGrab[9]},
|
|
{BONUS_GRAB + 8, BONUS_GRAB_TICS, NULL, &s_BonusGrab[10]},
|
|
{BONUS_GRAB + 9, 90, NULL, &s_BonusGrab[11]},
|
|
{BONUS_GRAB + 9, BONUS_GRAB_TICS, NULL, &s_BonusGrab[11]},
|
|
};
|
|
|
|
#if 1 // Turned off the standing animate because he looks like a FAG!
|
|
static STATE s_BonusRest[] =
|
|
{
|
|
{BONUS_REST + 0, BONUS_REST_TICS, NULL, &s_BonusRest[1]},
|
|
{BONUS_REST + 1, BONUS_REST_TICS, NULL, &s_BonusRest[2]},
|
|
{BONUS_REST + 2, BONUS_REST_TICS, NULL, &s_BonusRest[3]},
|
|
{BONUS_REST + 1, BONUS_REST_TICS, NULL, &s_BonusRest[0]},
|
|
};
|
|
#else
|
|
static STATE s_BonusRest[] =
|
|
{
|
|
{BONUS_REST + 0, BONUS_REST_TICS, NULL, &s_BonusRest[1]},
|
|
{BONUS_REST + 0, BONUS_REST_TICS, NULL, &s_BonusRest[0]},
|
|
};
|
|
#endif
|
|
|
|
static STATEp s_BonusAnim[] =
|
|
{
|
|
s_BonusPunch,
|
|
s_BonusKick,
|
|
s_BonusGrab
|
|
};
|
|
|
|
STATEp State = s_BonusRest;
|
|
|
|
int Tics = 0;
|
|
int line = 0;
|
|
SWBOOL BonusDone;
|
|
|
|
if (Level < 0) Level = 0;
|
|
|
|
twod->ClearScreen();
|
|
videoNextPage();
|
|
|
|
inputState.ClearAllInput();
|
|
|
|
totalclock = ototalclock = 0;
|
|
limit = synctics;
|
|
|
|
PlaySong(nullptr, ThemeSongs[1], ThemeTrack[1]);
|
|
|
|
// special case code because I don't care any more!
|
|
if (FinishAnim)
|
|
{
|
|
renderFlushPerms();
|
|
rotatesprite(0, 0, RS_SCALE, 0, 5120, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
rotatesprite(158<<16, 86<<16, RS_SCALE, 0, State->Pic, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
videoNextPage();
|
|
//FadeIn(0,0);
|
|
}
|
|
|
|
BonusDone = FALSE;
|
|
while (!BonusDone)
|
|
{
|
|
handleevents();
|
|
|
|
if (totalclock < ototalclock + limit)
|
|
{
|
|
continue;
|
|
}
|
|
ototalclock += limit;
|
|
|
|
if (inputState.CheckAllInput())
|
|
{
|
|
if (State >= s_BonusRest && State < &s_BonusRest[SIZ(s_BonusRest)])
|
|
{
|
|
State = s_BonusAnim[STD_RANDOM_RANGE(SIZ(s_BonusAnim))];
|
|
Tics = 0;
|
|
}
|
|
}
|
|
|
|
gStateControl(&State, &Tics);
|
|
|
|
twod->ClearScreen();
|
|
rotatesprite(0, 0, RS_SCALE, 0, 5120, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
|
|
if (UserMapName[0])
|
|
{
|
|
sprintf(ds,"%s",UserMapName);
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 20, ds,1,19);
|
|
}
|
|
else
|
|
{
|
|
if (PlayingLevel <= 1)
|
|
PlayingLevel = 1;
|
|
auto ds = currentLevel->DisplayName();
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 20, ds,1,19);
|
|
}
|
|
|
|
sprintf(ds,"Completed");
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 30, ds,1,19);
|
|
|
|
rotatesprite(158<<16, 86<<16, RS_SCALE, 0, State->Pic, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1);
|
|
|
|
#define BONUS_LINE(i) (50 + ((i)*20))
|
|
|
|
line = 0;
|
|
second_tics = (PlayClock/120);
|
|
minutes = (second_tics/60);
|
|
seconds = (second_tics%60);
|
|
sprintf(ds,"Your Time: %2d : %02d", minutes, seconds);
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(60, BONUS_LINE(line), ds,1,16);
|
|
|
|
if (!UserMapName[0])
|
|
{
|
|
line++;
|
|
sprintf(ds,"3D Realms Best Time: %d:%02d", currentLevel->designerTime/60, currentLevel->designerTime%60);
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(40, BONUS_LINE(line), ds,1,16);
|
|
|
|
line++;
|
|
sprintf(ds,"Par Time: %d:%02d", currentLevel->parTime/ 60, currentLevel->parTime%60);
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(40, BONUS_LINE(line), ds,1,16);
|
|
}
|
|
|
|
|
|
// always read secrets and kills from the first player
|
|
line++;
|
|
sprintf(ds,"Secrets: %d / %d", Player->SecretsFound, LevelSecrets);
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(60, BONUS_LINE(line), ds,1,16);
|
|
|
|
line++;
|
|
sprintf(ds,"Kills: %d / %d", Player->Kills, TotalKillable);
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(60, BONUS_LINE(line), ds,1,16);
|
|
|
|
|
|
sprintf(ds,"Press SPACE to continue");
|
|
MNU_MeasureString(ds, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 185, ds,1,19);
|
|
|
|
videoNextPage();
|
|
|
|
if (State == State->NextState)
|
|
BonusDone = TRUE;
|
|
}
|
|
|
|
StopSound();
|
|
}
|
|
|
|
void EndGameSequence(void)
|
|
{
|
|
SWBOOL anim_ok = TRUE;
|
|
//FadeOut(0, 5);
|
|
StopSound();
|
|
|
|
if ((adult_lockout || Global_PLock) && FinishAnim == ANIM_SUMO)
|
|
anim_ok = FALSE;
|
|
|
|
if (anim_ok)
|
|
playanm(FinishAnim);
|
|
|
|
BonusScreen();
|
|
|
|
ExitLevel = FALSE;
|
|
QuitFlag = FALSE;
|
|
AutoNet = FALSE;
|
|
|
|
if (FinishAnim == ANIM_ZILLA)
|
|
CreditsLevel();
|
|
|
|
ExitLevel = FALSE;
|
|
QuitFlag = FALSE;
|
|
AutoNet = FALSE;
|
|
|
|
if (SW_SHAREWARE)
|
|
{
|
|
Level = 0;
|
|
}
|
|
else
|
|
{
|
|
if (Level == 4 || Level == 20)
|
|
{
|
|
Level=0;
|
|
}
|
|
else
|
|
Level++;
|
|
}
|
|
}
|
|
|
|
void StatScreen(PLAYERp mpp)
|
|
{
|
|
extern SWBOOL FinishedLevel;
|
|
short w,h;
|
|
|
|
short rows,cols,i,j;
|
|
PLAYERp pp = NULL;
|
|
int x,y;
|
|
short death_total[MAX_SW_PLAYERS_REG];
|
|
short kills[MAX_SW_PLAYERS_REG];
|
|
short pal;
|
|
|
|
#define STAT_START_X 20
|
|
#define STAT_START_Y 85
|
|
#define STAT_OFF_Y 9
|
|
#define STAT_HEADER_Y 14
|
|
|
|
#define SM_SIZ(num) ((num)*4)
|
|
|
|
#define STAT_TABLE_X (STAT_START_X + SM_SIZ(15))
|
|
#define STAT_TABLE_XOFF SM_SIZ(6)
|
|
|
|
//ResetPalette(mpp);
|
|
COVER_SetReverb(0); // Reset reverb
|
|
mpp->Reverb = 0;
|
|
StopSound();
|
|
soundEngine->UpdateSounds((int)totalclock);
|
|
|
|
if (FinishAnim)
|
|
{
|
|
EndGameSequence();
|
|
return;
|
|
}
|
|
|
|
if (gNet.MultiGameType != MULTI_GAME_COMMBAT)
|
|
{
|
|
if (!FinishedLevel)
|
|
return;
|
|
BonusScreen();
|
|
return;
|
|
}
|
|
|
|
renderFlushPerms();
|
|
DrawStatScreen();
|
|
|
|
memset(death_total,0,sizeof(death_total));
|
|
memset(kills,0,sizeof(kills));
|
|
|
|
auto c = GStrings("MULTIPLAYER TOTALS");
|
|
MNU_MeasureString(c, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 68, c, 0, 0);
|
|
|
|
c = GStrings("TXTS_PRESSSPACE");
|
|
MNU_MeasureString(c, &w, &h);
|
|
MNU_DrawString(TEXT_TEST_COL(w), 189, c, 0, 0);
|
|
|
|
x = STAT_START_X;
|
|
y = STAT_START_Y;
|
|
|
|
// Hm.... how to translate this without messing up the formatting?
|
|
sprintf(ds," NAME 1 2 3 4 5 6 7 8 KILLS");
|
|
DisplayMiniBarSmString(mpp, x, y, 0, ds);
|
|
rows = OrigCommPlayers;
|
|
cols = OrigCommPlayers;
|
|
mpp = Player + myconnectindex;
|
|
|
|
y += STAT_HEADER_Y;
|
|
|
|
for (i = 0; i < rows; i++)
|
|
{
|
|
x = STAT_START_X;
|
|
pp = Player + i;
|
|
|
|
sprintf(ds,"%d", i+1);
|
|
DisplayMiniBarSmString(mpp, x, y, 0, ds);
|
|
|
|
sprintf(ds," %-13s", pp->PlayerName);
|
|
DisplayMiniBarSmString(mpp, x, y, User[pp->PlayerSprite]->spal, ds);
|
|
|
|
x = STAT_TABLE_X;
|
|
for (j = 0; j < cols; j++)
|
|
{
|
|
pal = 0;
|
|
death_total[j] += pp->KilledPlayer[j];
|
|
|
|
if (i == j)
|
|
{
|
|
// don't add kill for self or team player
|
|
pal = PALETTE_PLAYER0 + 4;
|
|
kills[i] -= pp->KilledPlayer[j]; // subtract self kills
|
|
}
|
|
else if (gNet.TeamPlay)
|
|
{
|
|
if (User[pp->PlayerSprite]->spal == User[Player[j].PlayerSprite]->spal)
|
|
{
|
|
// don't add kill for self or team player
|
|
pal = PALETTE_PLAYER0 + 4;
|
|
kills[i] -= pp->KilledPlayer[j]; // subtract self kills
|
|
}
|
|
else
|
|
kills[i] += pp->KilledPlayer[j]; // kills added here
|
|
}
|
|
else
|
|
{
|
|
kills[i] += pp->KilledPlayer[j]; // kills added here
|
|
}
|
|
|
|
sprintf(ds,"%d", pp->KilledPlayer[j]);
|
|
DisplayMiniBarSmString(mpp, x, y, pal, ds);
|
|
x += STAT_TABLE_XOFF;
|
|
}
|
|
|
|
y += STAT_OFF_Y;
|
|
}
|
|
|
|
|
|
// Deaths
|
|
|
|
x = STAT_START_X;
|
|
y += STAT_OFF_Y;
|
|
|
|
sprintf(ds," %s", GStrings("DEATHS"));
|
|
DisplayMiniBarSmString(mpp, x, y, 0, ds);
|
|
x = STAT_TABLE_X;
|
|
|
|
for (j = 0; j < cols; j++)
|
|
{
|
|
sprintf(ds,"%d",death_total[j]);
|
|
DisplayMiniBarSmString(mpp, x, y, 0, ds);
|
|
x += STAT_TABLE_XOFF;
|
|
}
|
|
|
|
x = STAT_START_X;
|
|
y += STAT_OFF_Y;
|
|
|
|
// Kills
|
|
x = STAT_TABLE_X + SM_SIZ(50);
|
|
y = STAT_START_Y + STAT_HEADER_Y;
|
|
|
|
for (i = 0; i < rows; i++)
|
|
{
|
|
pp = Player + i;
|
|
|
|
sprintf(ds,"%d", kills[i]); //pp->Kills);
|
|
DisplayMiniBarSmString(mpp, x, y, 0, ds);
|
|
|
|
y += STAT_OFF_Y;
|
|
}
|
|
|
|
videoNextPage();
|
|
|
|
inputState.ClearAllInput();
|
|
|
|
PlaySong(nullptr, ThemeSongs[1], ThemeTrack[1]);
|
|
|
|
while (!inputState.CheckAllInput())
|
|
{
|
|
handleevents();
|
|
}
|
|
|
|
StopSound();
|
|
}
|
|
|
|
void GameIntro(void)
|
|
{
|
|
|
|
DSPRINTF(ds,"GameIntro...");
|
|
MONO_PRINT(ds);
|
|
|
|
if (DemoPlaying)
|
|
return;
|
|
|
|
// this could probably be taken out and you could select skill level
|
|
// from menu to start the game
|
|
if (!CommEnabled && UserMapName[0])
|
|
return;
|
|
|
|
Level = 1;
|
|
|
|
|
|
|
|
PlayTheme();
|
|
|
|
if (!AutoNet)
|
|
{
|
|
LogoLevel();
|
|
//CreditsLevel();
|
|
IntroAnimLevel();
|
|
IntroAnimCount = 0;
|
|
}
|
|
|
|
MenuLevel();
|
|
}
|
|
|
|
void Control()
|
|
{
|
|
InitGame();
|
|
|
|
MONO_PRINT("InitGame done");
|
|
//MNU_InitMenus();
|
|
InGame = TRUE;
|
|
GameIntro();
|
|
|
|
while (!QuitFlag)
|
|
{
|
|
handleevents();
|
|
C_RunDelayedCommands();
|
|
|
|
NewLevel();
|
|
}
|
|
|
|
CleanExit = TRUE;
|
|
throw CExitEvent(0);
|
|
}
|
|
|
|
|
|
void _Assert(const char *expr, const char *strFile, unsigned uLine)
|
|
{
|
|
I_FatalError("Assertion failed: %s %s, line %u", expr, strFile, uLine);
|
|
}
|
|
|
|
|
|
|
|
void dsprintf(char *str, const char *format, ...)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist, format);
|
|
vsprintf(str, format, arglist);
|
|
va_end(arglist);
|
|
}
|
|
|
|
void dsprintf_null(char *str, const char *format, ...)
|
|
{
|
|
va_list arglist;
|
|
}
|
|
|
|
void getinput(SW_PACKET *, SWBOOL);
|
|
|
|
void MoveLoop(void)
|
|
{
|
|
int pnum;
|
|
|
|
getpackets();
|
|
|
|
if (PredictionOn && CommEnabled)
|
|
{
|
|
while (predictmovefifoplc < Player[myconnectindex].movefifoend)
|
|
{
|
|
DoPrediction(ppp);
|
|
}
|
|
}
|
|
|
|
//While you have new input packets to process...
|
|
if (!CommEnabled)
|
|
bufferjitter = 0;
|
|
|
|
while (Player[myconnectindex].movefifoend - movefifoplc > bufferjitter)
|
|
{
|
|
//Make sure you have at least 1 packet from everyone else
|
|
for (pnum=connecthead; pnum>=0; pnum=connectpoint2[pnum])
|
|
{
|
|
if (movefifoplc == Player[pnum].movefifoend)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Pnum is >= 0 only if last loop was broken, meaning a player wasn't caught up
|
|
if (pnum >= 0)
|
|
break;
|
|
|
|
domovethings();
|
|
|
|
#if DEBUG
|
|
//if (DemoSyncRecord)
|
|
// demosync_record();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
void InitPlayerGameSettings(void)
|
|
{
|
|
int pnum;
|
|
|
|
// don't jack with auto aim settings if DemoMode is going
|
|
// what the hell did I do this for?????????
|
|
//if (DemoMode)
|
|
// return;
|
|
|
|
if (CommEnabled)
|
|
{
|
|
// everyone gets the same Auto Aim
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
if (gNet.AutoAim)
|
|
SET(Player[pnum].Flags, PF_AUTO_AIM);
|
|
else
|
|
RESET(Player[pnum].Flags, PF_AUTO_AIM);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cl_autoaim)
|
|
SET(Player[myconnectindex].Flags, PF_AUTO_AIM);
|
|
else
|
|
RESET(Player[myconnectindex].Flags, PF_AUTO_AIM);
|
|
}
|
|
}
|
|
|
|
|
|
void InitRunLevel(void)
|
|
{
|
|
if (DemoEdit)
|
|
return;
|
|
|
|
if (LoadGameOutsideMoveLoop)
|
|
{
|
|
int SavePlayClock;
|
|
extern int PlayClock;
|
|
LoadGameOutsideMoveLoop = FALSE;
|
|
// contains what is needed from calls below
|
|
if (snd_ambience)
|
|
StartAmbientSound();
|
|
// crappy little hack to prevent play clock from being overwritten
|
|
// for load games
|
|
SavePlayClock = PlayClock;
|
|
InitTimingVars();
|
|
PlayClock = SavePlayClock;
|
|
MONO_PRINT("Done with InitRunLevel");
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
// ensure we are through the initialization code before sending the game
|
|
// version. Otherwise, it is possible to send this too early and have it
|
|
// blown away on the other side.
|
|
waitforeverybody();
|
|
#endif
|
|
|
|
SendVersion(GameVersion);
|
|
|
|
waitforeverybody();
|
|
|
|
Mus_Stop();
|
|
|
|
if (Bstrcasecmp(CacheLastLevel, LevelName) != 0)
|
|
DoTheCache();
|
|
|
|
// auto aim / auto run / etc
|
|
InitPlayerGameSettings();
|
|
|
|
// send packets with player info
|
|
InitNetPlayerOptions();
|
|
|
|
// Initialize Game part of network code (When ready2send != 0)
|
|
InitNetVars();
|
|
|
|
{
|
|
if (Level == 0)
|
|
{
|
|
PlaySong(nullptr, currentLevel->music, 1 + RANDOM_RANGE(10));
|
|
}
|
|
else
|
|
{
|
|
PlaySong(currentLevel->labelName, currentLevel->music, currentLevel->cdSongId);
|
|
}
|
|
}
|
|
|
|
InitPrediction(&Player[myconnectindex]);
|
|
|
|
if (!DemoInitOnce)
|
|
DemoRecordSetup();
|
|
|
|
// everything has been inited at least once for RECORD
|
|
DemoInitOnce = TRUE;
|
|
|
|
//DebugWriteLoc(__FILE__, __LINE__);
|
|
waitforeverybody();
|
|
|
|
CheckVersion(GameVersion);
|
|
|
|
// IMPORTANT - MUST be right before game loop AFTER waitforeverybody
|
|
InitTimingVars();
|
|
|
|
if (snd_ambience)
|
|
StartAmbientSound();
|
|
}
|
|
|
|
void RunLevel(void)
|
|
{
|
|
InitRunLevel();
|
|
|
|
#if 0
|
|
waitforeverybody();
|
|
#endif
|
|
ready2send = 1;
|
|
|
|
while (TRUE)
|
|
{
|
|
handleevents();
|
|
C_RunDelayedCommands();
|
|
D_ProcessEvents();
|
|
if (LoadGameOutsideMoveLoop)
|
|
{
|
|
return; // Stop the game loop if a savegame was loaded from the menu.
|
|
}
|
|
|
|
updatePauseStatus();
|
|
|
|
if (paused)
|
|
{
|
|
ototalclock = (int)totalclock - (120 / synctics);
|
|
buttonMap.ResetButtonStates();
|
|
}
|
|
else
|
|
{
|
|
while (ready2send && (totalclock >= ototalclock + synctics))
|
|
{
|
|
UpdateInputs();
|
|
MoveLoop();
|
|
}
|
|
|
|
// Get input again to update q16ang/q16horiz.
|
|
if (!PedanticMode)
|
|
getinput(&loc, TRUE);
|
|
}
|
|
|
|
drawscreen(Player + screenpeek);
|
|
|
|
if (QuitFlag)
|
|
break;
|
|
|
|
if (ExitLevel)
|
|
{
|
|
ExitLevel = FALSE;
|
|
break;
|
|
}
|
|
|
|
timerUpdateClock();
|
|
}
|
|
|
|
ready2send = 0;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
char notshareware;
|
|
const char *arg_switch;
|
|
short arg_match_len;
|
|
const char *arg_fmt;
|
|
const char *arg_descr;
|
|
} CLI_ARG;
|
|
|
|
|
|
|
|
|
|
CLI_ARG cli_arg[] =
|
|
{
|
|
{0, "/?", 2, "-?", "This help message" },
|
|
//#ifndef SW_SHAREWARE
|
|
//{"/l", 2, "-l#", "Level (1-11)" },
|
|
//{"/v", 2, "-v#", "Volume (1-3)" },
|
|
{1, "/map", 4, "-map [mapname]", "Load a map" },
|
|
{1, "/nocdaudio", 5, "-nocd<audio>", "No CD Red Book Audio" },
|
|
//#endif
|
|
|
|
{0, "/name", 5, "-name [playername]", "Player Name" },
|
|
{0, "/s", 2, "-s#", "Skill (1-4)" },
|
|
{0, "/f#", 3, "-f#", "Packet Duplication - 2, 4, 8" },
|
|
{0, "/nopredict", 7, "-nopred<ict>", "Disable Net Prediction Method" },
|
|
{0, "/level#", 5, "-level#", "Start at level# (Shareware: 1-4, full version 1-28)" },
|
|
{0, "/dr", 3, "-dr[filename.dmo]", "Demo record. NOTE: Must use -level# with this option." },
|
|
{0, "/dp", 3, "-dp[filename.dmo]", "Demo playback. NOTE: Must use -level# with this option." },
|
|
{0, "/m", 6, "-monst<ers>", "No Monsters" },
|
|
{0, "/nodemo", 6, "-nodemo", "No demos on game startup" },
|
|
{0, "/nometers", 9, "-nometers", "Don't show air or boss meter bars in game"},
|
|
{0, "/movescale #", 9, "-movescale", "Adjust movement scale: 256 = 1 unit"},
|
|
{0, "/turnscale #", 9, "-turnscale", "Adjust turning scale: 256 = 1 unit"},
|
|
{0, "/extcompat", 9, "-extcompat", "Controller compatibility mode (with Duke 3D)"},
|
|
{1, "/g#", 2, "-g[filename.grp]", "Load an extra GRP or ZIP file"},
|
|
{1, "/h#", 2, "-h[filename.def]", "Use filename.def instead of SW.DEF"},
|
|
{0, "/setup", 5, "-setup", "Displays the configuration dialogue box"},
|
|
#if DEBUG
|
|
{0, "/coop", 5, "-coop#", "Single Player Cooperative Mode" },
|
|
{0, "/commbat", 8, "-commbat#", "Single Player Commbat Mode" },
|
|
{0, "/debug", 6, "-debug", "Debug Help Options" },
|
|
#endif
|
|
|
|
#if 0 //def NET_MODE_MASTER_SLAVE
|
|
{0, "/broadcast", 6, "-broad<cast>", "Broadcast network method (default)" },
|
|
{0, "/masterslave", 7, "-master<slave>", "Master/Slave network method" },
|
|
#endif
|
|
};
|
|
|
|
#if 0
|
|
Map -> User Map Name
|
|
Auto -> Auto Start Game
|
|
Rules -> 0=WangBang 1=WangBang (No Respawn) 2=CoOperative
|
|
Level -> 0 to 24(?)
|
|
Enemy -> 0=None 1=Easy 2=Norm 3=Hard 4=Insane
|
|
Markers -> 0=Off 1=On
|
|
Team -> 0=Off 1=On
|
|
HurtTeam -> 0=Off 1=On
|
|
KillLimit -> 0=Infinite 1=10 2=20 3=30 4=40 5=50 6=60 7=70 8=80 9=90 10=100
|
|
TimeLimit -> 0=Infinite 1=3 2=5 3=10 4=20 5=30 6=45 7=60
|
|
Color -> 0=Brown 1=Purple 2=Red 3=Yellow 4=Olive 5=Green
|
|
Nuke -> 0=Off 1=On
|
|
|
|
Example Command Line :
|
|
sw -map testmap.map -autonet 0,0,1,1,1,0,3,2,1,1 -f4 -name 1234567890 -net 12345678
|
|
commit -map grenade -autonet 0,0,1,1,1,0,3,2,1,1 -name frank
|
|
#endif
|
|
|
|
char isShareware = FALSE;
|
|
|
|
int DetectShareware(void)
|
|
{
|
|
return (isShareware = !!(g_gameType & GAMEFLAG_SHAREWARE));
|
|
}
|
|
|
|
|
|
void CommandLineHelp(char const * const * argv)
|
|
{
|
|
}
|
|
|
|
static const char* actions[] = {
|
|
"Move_Forward",
|
|
"Move_Backward",
|
|
"Turn_Left",
|
|
"Turn_Right",
|
|
"Strafe",
|
|
"Fire",
|
|
"Open",
|
|
"Run",
|
|
"Alt_Fire", // Duke3D", Blood
|
|
"Jump",
|
|
"Crouch",
|
|
"Look_Up",
|
|
"Look_Down",
|
|
"Look_Left",
|
|
"Look_Right",
|
|
"Strafe_Left",
|
|
"Strafe_Right",
|
|
"Aim_Up",
|
|
"Aim_Down",
|
|
"Weapon_1",
|
|
"Weapon_2",
|
|
"Weapon_3",
|
|
"Weapon_4",
|
|
"Weapon_5",
|
|
"Weapon_6",
|
|
"Weapon_7",
|
|
"Weapon_8",
|
|
"Weapon_9",
|
|
"Weapon_10",
|
|
"Inventory",
|
|
"Inventory_Left",
|
|
"Inventory_Right",
|
|
"NightVision",
|
|
"MedKit",
|
|
"TurnAround",
|
|
"SendMessage",
|
|
"Map",
|
|
"Shrink_Screen",
|
|
"Enlarge_Screen",
|
|
"Center_View",
|
|
"Holster_Weapon",
|
|
"Show_Opponents_Weapon",
|
|
"Map_Follow_Mode",
|
|
"See_Coop_View",
|
|
"Mouse_Aiming",
|
|
"Toggle_Crosshair",
|
|
"Next_Weapon",
|
|
"Previous_Weapon",
|
|
"Dpad_Select",
|
|
"Dpad_Aiming",
|
|
"Last_Weapon",
|
|
"Alt_Weapon",
|
|
"Third_Person_View",
|
|
"Toggle_Crouch", // This is the last one used by EDuke32"",
|
|
"Smoke_Bomb",
|
|
"Gas_Bomb",
|
|
"Flash_Bomb",
|
|
"Caltrops",
|
|
|
|
};
|
|
|
|
int32_t GameInterface::app_main()
|
|
{
|
|
int i;
|
|
extern int MovesPerPacket;
|
|
void DoSector(void);
|
|
void gameinput(void);
|
|
int cnt = 0;
|
|
|
|
InitCheats();
|
|
buttonMap.SetButtons(actions, NUM_ACTIONS);
|
|
automapping = 1;
|
|
|
|
gs = gs_defaults;
|
|
|
|
hud_size.Callback();
|
|
|
|
if (!DetectShareware())
|
|
{
|
|
if (SW_SHAREWARE) Printf("Detected shareware GRP\n");
|
|
else Printf("Detected registered GRP\n");
|
|
}
|
|
|
|
for (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");
|
|
|
|
UserMapName[0] = '\0';
|
|
|
|
registerosdcommands();
|
|
|
|
Control();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ManualPlayerInsert(PLAYERp pp)
|
|
{
|
|
PLAYERp npp = Player + numplayers;
|
|
|
|
if (numplayers < MAX_SW_PLAYERS)
|
|
{
|
|
connectpoint2[numplayers - 1] = numplayers;
|
|
connectpoint2[numplayers] = -1;
|
|
|
|
npp->posx = pp->posx;
|
|
npp->posy = pp->posy;
|
|
npp->posz = pp->posz;
|
|
npp->q16ang = pp->q16ang;
|
|
npp->cursectnum = pp->cursectnum;
|
|
|
|
myconnectindex = numplayers;
|
|
screenpeek = numplayers;
|
|
|
|
sprintf(Player[myconnectindex].PlayerName,"PLAYER %d",myconnectindex+1);
|
|
|
|
Player[numplayers].movefifoend = Player[0].movefifoend;
|
|
|
|
// If IsAI = TRUE, new player will be a bot
|
|
Player[myconnectindex].IsAI = FALSE;
|
|
|
|
numplayers++;
|
|
}
|
|
|
|
}
|
|
|
|
void BotPlayerInsert(PLAYERp pp)
|
|
{
|
|
PLAYERp npp = Player + numplayers;
|
|
|
|
if (numplayers < MAX_SW_PLAYERS)
|
|
{
|
|
connectpoint2[numplayers - 1] = numplayers;
|
|
connectpoint2[numplayers] = -1;
|
|
|
|
npp->posx = pp->posx;
|
|
npp->posy = pp->posy;
|
|
npp->posz = pp->posz-Z(100);
|
|
npp->q16ang = pp->q16ang;
|
|
npp->cursectnum = pp->cursectnum;
|
|
|
|
//myconnectindex = numplayers;
|
|
//screenpeek = numplayers;
|
|
|
|
sprintf(Player[numplayers].PlayerName,"BOT %d",numplayers+1);
|
|
|
|
Player[numplayers].movefifoend = Player[0].movefifoend;
|
|
|
|
// If IsAI = TRUE, new player will be a bot
|
|
Player[numplayers].IsAI = TRUE;
|
|
|
|
numplayers++;
|
|
}
|
|
}
|
|
|
|
void
|
|
ManualPlayerDelete(void)
|
|
{
|
|
short i, nexti;
|
|
USERp u;
|
|
PLAYERp pp;
|
|
|
|
if (numplayers > 1)
|
|
{
|
|
numplayers--;
|
|
connectpoint2[numplayers - 1] = -1;
|
|
|
|
pp = Player + numplayers;
|
|
|
|
KillSprite(pp->PlayerSprite);
|
|
pp->PlayerSprite = -1;
|
|
|
|
// Make sure enemys "forget" about deleted player
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_ENEMY], i, nexti)
|
|
{
|
|
u = User[i];
|
|
if (u->tgt_sp == pp->SpriteP)
|
|
u->tgt_sp = Player[0].SpriteP;
|
|
}
|
|
|
|
if (myconnectindex >= numplayers)
|
|
myconnectindex = 0;
|
|
|
|
if (screenpeek >= numplayers)
|
|
screenpeek = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
char WangBangMacro[10][64];
|
|
|
|
void
|
|
FunctionKeys(PLAYERp pp)
|
|
{
|
|
static int rts_delay = 0;
|
|
int fn_key = 0;
|
|
|
|
rts_delay++;
|
|
|
|
if (inputState.GetKeyStatus(sc_F1)) { fn_key = 1; }
|
|
if (inputState.GetKeyStatus(sc_F2)) { fn_key = 2; }
|
|
if (inputState.GetKeyStatus(sc_F3)) { fn_key = 3; }
|
|
if (inputState.GetKeyStatus(sc_F4)) { fn_key = 4; }
|
|
if (inputState.GetKeyStatus(sc_F5)) { fn_key = 5; }
|
|
if (inputState.GetKeyStatus(sc_F6)) { fn_key = 6; }
|
|
if (inputState.GetKeyStatus(sc_F7)) { fn_key = 7; }
|
|
if (inputState.GetKeyStatus(sc_F8)) { fn_key = 8; }
|
|
if (inputState.GetKeyStatus(sc_F9)) { fn_key = 9; }
|
|
if (inputState.GetKeyStatus(sc_F10)) { fn_key = 10; }
|
|
|
|
if (inputState.AltPressed())
|
|
{
|
|
if (rts_delay > 16 && fn_key && CommEnabled && !adult_lockout && !Global_PLock)
|
|
{
|
|
inputState.ClearKeyStatus(sc_F1 + fn_key - 1);
|
|
|
|
rts_delay = 0;
|
|
|
|
PlaySoundRTS(fn_key);
|
|
|
|
if (CommEnabled)
|
|
{
|
|
PACKET_RTS p;
|
|
|
|
p.PacketType = PACKET_TYPE_RTS;
|
|
p.RTSnum = fn_key;
|
|
|
|
netbroadcastpacket((uint8_t*)(&p), sizeof(p)); // TENSW
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (inputState.ShiftPressed())
|
|
{
|
|
if (fn_key && CommEnabled)
|
|
{
|
|
inputState.ClearKeyStatus(sc_Escape);
|
|
inputState.ClearKeyStatus(sc_F1 + fn_key - 1);
|
|
|
|
if (CommEnabled)
|
|
{
|
|
short pnum;
|
|
|
|
sprintf(ds,"SENT: %s",**CombatMacros[fn_key-1]);
|
|
adduserquote(ds);
|
|
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
if (pnum != myconnectindex)
|
|
{
|
|
sprintf(ds,"%s: %s",pp->PlayerName, **CombatMacros[fn_key - 1]);
|
|
SW_SendMessage(pnum, ds);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// F7 VIEW control
|
|
if (buttonMap.ButtonDown(gamefunc_Third_Person_View))
|
|
{
|
|
buttonMap.ClearButton(gamefunc_Third_Person_View);
|
|
|
|
if (SHIFTS_IS_PRESSED)
|
|
{
|
|
if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE))
|
|
pp->view_outside_dang = NORM_ANGLE(pp->view_outside_dang + 256);
|
|
}
|
|
else
|
|
{
|
|
if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE))
|
|
{
|
|
RESET(pp->Flags, PF_VIEW_FROM_OUTSIDE);
|
|
}
|
|
else
|
|
{
|
|
SET(pp->Flags, PF_VIEW_FROM_OUTSIDE);
|
|
pp->camera_dist = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
short MirrorDelay;
|
|
|
|
double elapsedInputTicks;
|
|
double scaleAdjustmentToInterval(double x) { return x * (120 / synctics) / (1000.0 / elapsedInputTicks); }
|
|
|
|
void DoPlayerTurn(PLAYERp pp, fix16_t *pq16ang, fix16_t q16angvel);
|
|
void DoPlayerHorizon(PLAYERp pp, fix16_t *pq16horiz, fix16_t q16aimvel);
|
|
|
|
void
|
|
getinput(SW_PACKET *loc, SWBOOL tied)
|
|
{
|
|
int i;
|
|
PLAYERp pp = Player + myconnectindex;
|
|
PLAYERp newpp = Player + myconnectindex;
|
|
int inv_hotkey = 0;
|
|
|
|
#define TURBOTURNTIME (120/8)
|
|
#define NORMALTURN (12+6)
|
|
#define RUNTURN (28)
|
|
#define PREAMBLETURN 3
|
|
#define NORMALKEYMOVE 35
|
|
#define MAXVEL ((NORMALKEYMOVE*2)+10)
|
|
#define MAXSVEL ((NORMALKEYMOVE*2)+10)
|
|
#define MAXANGVEL 100
|
|
#define MAXHORIZVEL 128
|
|
#define SET_LOC_KEY(loc, sync_num, key_test) SET(loc, ((!!(key_test)) << (sync_num)))
|
|
|
|
static int32_t turnheldtime;
|
|
int32_t momx, momy;
|
|
|
|
extern SWBOOL MenuButtonAutoAim;
|
|
|
|
if (Prediction && CommEnabled)
|
|
{
|
|
newpp = ppp;
|
|
}
|
|
|
|
static double lastInputTicks;
|
|
|
|
auto const currentHiTicks = timerGetHiTicks();
|
|
elapsedInputTicks = currentHiTicks - lastInputTicks;
|
|
|
|
lastInputTicks = currentHiTicks;
|
|
|
|
// MAKE SURE THIS WILL GET SET
|
|
SET_LOC_KEY(loc->bits, SK_QUIT_GAME, MultiPlayQuitFlag);
|
|
|
|
bool mouseaim = in_mousemode || buttonMap.ButtonDown(gamefunc_Mouse_Aiming);
|
|
|
|
if (!CommEnabled)
|
|
{
|
|
// Go back to the source to set this - the old code here was catastrophically bad.
|
|
// this needs to be fixed properly - as it is this can never be compatible with demo playback.
|
|
|
|
if (mouseaim)
|
|
SET(Player[myconnectindex].Flags, PF_MOUSE_AIMING_ON);
|
|
else
|
|
RESET(Player[myconnectindex].Flags, PF_MOUSE_AIMING_ON);
|
|
|
|
if (cl_autoaim)
|
|
SET(Player[myconnectindex].Flags, PF_AUTO_AIM);
|
|
else
|
|
RESET(Player[myconnectindex].Flags, PF_AUTO_AIM);
|
|
}
|
|
|
|
ControlInfo info;
|
|
CONTROL_GetInput(&info);
|
|
|
|
if (paused)
|
|
return;
|
|
|
|
// MAP KEY
|
|
if (buttonMap.ButtonDown(gamefunc_Map))
|
|
{
|
|
buttonMap.ClearButton(gamefunc_Map);
|
|
|
|
// Init follow coords
|
|
Follow_posx = pp->posx;
|
|
Follow_posy = pp->posy;
|
|
|
|
if (dimensionmode == 3)
|
|
dimensionmode = 5;
|
|
else if (dimensionmode == 5)
|
|
dimensionmode = 6;
|
|
else
|
|
{
|
|
MirrorDelay = 1;
|
|
dimensionmode = 3;
|
|
ScrollMode2D = FALSE;
|
|
}
|
|
}
|
|
|
|
// Toggle follow map mode on/off
|
|
if (dimensionmode == 5 || dimensionmode == 6)
|
|
{
|
|
if (buttonMap.ButtonDown(gamefunc_Map_Follow_Mode))
|
|
{
|
|
buttonMap.ClearButton(gamefunc_Map_Follow_Mode);
|
|
ScrollMode2D = !ScrollMode2D;
|
|
Follow_posx = pp->posx;
|
|
Follow_posy = pp->posy;
|
|
}
|
|
}
|
|
|
|
// If in 2D follow mode, scroll around using glob vars
|
|
// Tried calling this in domovethings, but key response it too poor, skips key presses
|
|
// Note: ScrollMode2D = Follow mode, so this get called only during follow mode
|
|
if (!tied && ScrollMode2D && pp == Player + myconnectindex && !Prediction)
|
|
MoveScrollMode2D(Player + myconnectindex);
|
|
|
|
// !JIM! Added M_Active() so that you don't move at all while using menus
|
|
if (M_Active() || ScrollMode2D || InputMode)
|
|
return;
|
|
|
|
SET_LOC_KEY(loc->bits, SK_SPACE_BAR, buttonMap.ButtonDown(gamefunc_Open));
|
|
|
|
int const running = G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run));
|
|
int32_t turnamount;
|
|
int32_t keymove;
|
|
|
|
// The function DoPlayerTurn() scales the player's q16angvel by 1.40625, so store as constant
|
|
// and use to scale back player's aim and ang values for a consistent feel between games.
|
|
float const angvelScale = 1.40625f;
|
|
float const aimvelScale = 1.203125f;
|
|
|
|
// Shadow Warrior has a ticrate of 40, 25% more than the other games, so store below constant
|
|
// for dividing controller input to match speed input speed of other games.
|
|
float const ticrateScale = 0.75f;
|
|
|
|
if (running)
|
|
{
|
|
if (pp->sop_control)
|
|
turnamount = RUNTURN * 3;
|
|
else
|
|
turnamount = RUNTURN;
|
|
|
|
keymove = NORMALKEYMOVE << 1;
|
|
}
|
|
else
|
|
{
|
|
if (pp->sop_control)
|
|
turnamount = NORMALTURN * 3;
|
|
else
|
|
turnamount = NORMALTURN;
|
|
|
|
keymove = NORMALKEYMOVE;
|
|
}
|
|
|
|
if (tied)
|
|
keymove = 0;
|
|
|
|
int32_t svel = 0, vel = 0;
|
|
fix16_t q16aimvel = 0, q16angvel = 0;
|
|
|
|
if (buttonMap.ButtonDown(gamefunc_Strafe) && !pp->sop)
|
|
{
|
|
svel -= (info.mousex * ticrateScale) * 4.f;
|
|
svel -= info.dyaw * keymove;
|
|
}
|
|
else
|
|
{
|
|
q16angvel = fix16_sadd(q16angvel, fix16_from_float(info.mousex / angvelScale));
|
|
q16angvel = fix16_sadd(q16angvel, fix16_from_dbl(scaleAdjustmentToInterval((info.dyaw * ticrateScale) / angvelScale)));
|
|
}
|
|
|
|
if (mouseaim)
|
|
q16aimvel = fix16_ssub(q16aimvel, fix16_from_float(info.mousey / aimvelScale));
|
|
else
|
|
vel -= (info.mousey * ticrateScale) * 8.f;
|
|
|
|
if (in_mouseflip)
|
|
q16aimvel = -q16aimvel;
|
|
|
|
q16aimvel -= fix16_from_dbl(scaleAdjustmentToInterval((info.dpitch * ticrateScale) / aimvelScale));
|
|
svel -= info.dx * keymove;
|
|
vel -= info.dz * keymove;
|
|
|
|
if (buttonMap.ButtonDown(gamefunc_Strafe) && !pp->sop)
|
|
{
|
|
if (buttonMap.ButtonDown(gamefunc_Turn_Left))
|
|
svel -= -keymove;
|
|
if (buttonMap.ButtonDown(gamefunc_Turn_Right))
|
|
svel -= keymove;
|
|
}
|
|
else
|
|
{
|
|
if (buttonMap.ButtonDown(gamefunc_Turn_Left) || (buttonMap.ButtonDown(gamefunc_Strafe_Left) && pp->sop))
|
|
{
|
|
turnheldtime += synctics;
|
|
if (PedanticMode)
|
|
{
|
|
if (turnheldtime >= TURBOTURNTIME)
|
|
q16angvel -= fix16_from_int(turnamount);
|
|
else
|
|
q16angvel -= fix16_from_int(PREAMBLETURN);
|
|
}
|
|
else
|
|
q16angvel = fix16_ssub(q16angvel, fix16_from_float(scaleAdjustmentToInterval((turnheldtime >= TURBOTURNTIME) ? turnamount : PREAMBLETURN)));
|
|
}
|
|
else if (buttonMap.ButtonDown(gamefunc_Turn_Right) || (buttonMap.ButtonDown(gamefunc_Strafe_Right) && pp->sop))
|
|
{
|
|
turnheldtime += synctics;
|
|
if (PedanticMode)
|
|
{
|
|
if (turnheldtime >= TURBOTURNTIME)
|
|
q16angvel += fix16_from_int(turnamount);
|
|
else
|
|
q16angvel += fix16_from_int(PREAMBLETURN);
|
|
}
|
|
else
|
|
q16angvel = fix16_sadd(q16angvel, fix16_from_float(scaleAdjustmentToInterval((turnheldtime >= TURBOTURNTIME) ? turnamount : PREAMBLETURN)));
|
|
}
|
|
else
|
|
{
|
|
turnheldtime = 0;
|
|
}
|
|
}
|
|
|
|
if (buttonMap.ButtonDown(gamefunc_Strafe_Left) && !pp->sop)
|
|
svel += keymove;
|
|
|
|
if (buttonMap.ButtonDown(gamefunc_Strafe_Right) && !pp->sop)
|
|
svel += -keymove;
|
|
|
|
if (buttonMap.ButtonDown(gamefunc_Move_Forward))
|
|
{
|
|
vel += keymove;
|
|
//DSPRINTF(ds,"vel key %d",vel);
|
|
//DebugWriteString(ds);
|
|
}
|
|
else
|
|
{
|
|
//DSPRINTF(ds,"vel %d",vel);
|
|
//DebugWriteString(ds);
|
|
}
|
|
|
|
if (buttonMap.ButtonDown(gamefunc_Move_Backward))
|
|
vel += -keymove;
|
|
|
|
q16angvel = fix16_clamp(q16angvel, -fix16_from_int(MAXANGVEL), fix16_from_int(MAXANGVEL));
|
|
q16aimvel = fix16_clamp(q16aimvel, -fix16_from_int(MAXHORIZVEL), fix16_from_int(MAXHORIZVEL));
|
|
|
|
void DoPlayerTeleportPause(PLAYERp pp);
|
|
if (PedanticMode)
|
|
{
|
|
q16angvel = fix16_floor(q16angvel);
|
|
q16aimvel = fix16_floor(q16aimvel);
|
|
}
|
|
else
|
|
{
|
|
fix16_t prevcamq16ang = pp->camq16ang, prevcamq16horiz = pp->camq16horiz;
|
|
|
|
if (TEST(pp->Flags2, PF2_INPUT_CAN_TURN))
|
|
DoPlayerTurn(pp, &pp->camq16ang, q16angvel);
|
|
if (TEST(pp->Flags2, PF2_INPUT_CAN_AIM))
|
|
DoPlayerHorizon(pp, &pp->camq16horiz, q16aimvel);
|
|
pp->oq16ang += pp->camq16ang - prevcamq16ang;
|
|
pp->oq16horiz += pp->camq16horiz - prevcamq16horiz;
|
|
}
|
|
|
|
loc->vel += vel;
|
|
loc->svel += svel;
|
|
|
|
if (!tied)
|
|
{
|
|
vel = clamp(loc->vel, -MAXVEL, MAXVEL);
|
|
svel = clamp(loc->svel, -MAXSVEL, MAXSVEL);
|
|
|
|
momx = mulscale9(vel, sintable[NORM_ANGLE(fix16_to_int(newpp->q16ang) + 512)]);
|
|
momy = mulscale9(vel, sintable[NORM_ANGLE(fix16_to_int(newpp->q16ang))]);
|
|
|
|
momx += mulscale9(svel, sintable[NORM_ANGLE(fix16_to_int(newpp->q16ang))]);
|
|
momy += mulscale9(svel, sintable[NORM_ANGLE(fix16_to_int(newpp->q16ang) + 1536)]);
|
|
|
|
loc->vel = momx;
|
|
loc->svel = momy;
|
|
}
|
|
|
|
loc->q16angvel += q16angvel;
|
|
loc->q16aimvel += q16aimvel;
|
|
|
|
if (!CommEnabled)
|
|
{
|
|
// What a mess...:?
|
|
#if 0
|
|
if (MenuButtonAutoAim)
|
|
{
|
|
MenuButtonAutoAim = FALSE;
|
|
if ((!!TEST(pp->Flags, PF_AUTO_AIM)) != !!cl_autoaim)
|
|
SET_LOC_KEY(loc->bits, SK_AUTO_AIM, TRUE);
|
|
}
|
|
#endif
|
|
}
|
|
else if (inputState.GetKeyStatus(sc_Pause))
|
|
{
|
|
SET_LOC_KEY(loc->bits, SK_PAUSE, true);
|
|
inputState.ClearKeyStatus(sc_Pause);
|
|
}
|
|
|
|
SET_LOC_KEY(loc->bits, SK_CENTER_VIEW, buttonMap.ButtonDown(gamefunc_Center_View));
|
|
|
|
SET_LOC_KEY(loc->bits, SK_RUN, buttonMap.ButtonDown(gamefunc_Run));
|
|
SET_LOC_KEY(loc->bits, SK_SHOOT, buttonMap.ButtonDown(gamefunc_Fire));
|
|
|
|
// actually snap
|
|
SET_LOC_KEY(loc->bits, SK_SNAP_UP, buttonMap.ButtonDown(gamefunc_Aim_Up));
|
|
SET_LOC_KEY(loc->bits, SK_SNAP_DOWN, buttonMap.ButtonDown(gamefunc_Aim_Down));
|
|
|
|
// actually just look
|
|
SET_LOC_KEY(loc->bits, SK_LOOK_UP, buttonMap.ButtonDown(gamefunc_Look_Up));
|
|
SET_LOC_KEY(loc->bits, SK_LOOK_DOWN, buttonMap.ButtonDown(gamefunc_Look_Down));
|
|
|
|
for (i = 0; i < MAX_WEAPONS_KEYS; i++)
|
|
{
|
|
if (buttonMap.ButtonDown(gamefunc_Weapon_1 + i))
|
|
{
|
|
SET(loc->bits, i + 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (buttonMap.ButtonPressed(gamefunc_Next_Weapon))
|
|
{
|
|
USERp u = User[pp->PlayerSprite];
|
|
short next_weapon = u->WeaponNum + 1;
|
|
short start_weapon;
|
|
|
|
buttonMap.ClearButton(gamefunc_Next_Weapon);
|
|
|
|
start_weapon = u->WeaponNum + 1;
|
|
|
|
if (u->WeaponNum == WPN_SWORD)
|
|
start_weapon = WPN_STAR;
|
|
|
|
if (u->WeaponNum == WPN_FIST)
|
|
{
|
|
next_weapon = 14;
|
|
}
|
|
else
|
|
{
|
|
next_weapon = -1;
|
|
for (i = start_weapon; TRUE; i++)
|
|
{
|
|
if (i >= MAX_WEAPONS_KEYS)
|
|
{
|
|
next_weapon = 13;
|
|
break;
|
|
}
|
|
|
|
if (TEST(pp->WpnFlags, BIT(i)) && pp->WpnAmmo[i])
|
|
{
|
|
next_weapon = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SET(loc->bits, next_weapon + 1);
|
|
}
|
|
|
|
|
|
if (buttonMap.ButtonPressed(gamefunc_Previous_Weapon))
|
|
{
|
|
USERp u = User[pp->PlayerSprite];
|
|
short prev_weapon = u->WeaponNum - 1;
|
|
short start_weapon;
|
|
|
|
buttonMap.ClearButton(gamefunc_Previous_Weapon);
|
|
|
|
start_weapon = u->WeaponNum - 1;
|
|
|
|
if (u->WeaponNum == WPN_SWORD)
|
|
{
|
|
prev_weapon = 13;
|
|
}
|
|
else if (u->WeaponNum == WPN_STAR)
|
|
{
|
|
prev_weapon = 14;
|
|
}
|
|
else
|
|
{
|
|
prev_weapon = -1;
|
|
for (i = start_weapon; TRUE; i--)
|
|
{
|
|
if (i <= -1)
|
|
i = WPN_HEART;
|
|
|
|
if (TEST(pp->WpnFlags, BIT(i)) && pp->WpnAmmo[i])
|
|
{
|
|
prev_weapon = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SET(loc->bits, prev_weapon + 1);
|
|
}
|
|
|
|
if (buttonMap.ButtonDown(gamefunc_Alt_Weapon))
|
|
{
|
|
buttonMap.ClearButton(gamefunc_Alt_Weapon);
|
|
USERp u = User[pp->PlayerSprite];
|
|
short const which_weapon = u->WeaponNum + 1;
|
|
SET(loc->bits, which_weapon);
|
|
}
|
|
|
|
|
|
inv_hotkey = 0;
|
|
if (buttonMap.ButtonDown(gamefunc_MedKit))
|
|
inv_hotkey = INVENTORY_MEDKIT+1;
|
|
if (buttonMap.ButtonDown(gamefunc_Smoke_Bomb))
|
|
inv_hotkey = INVENTORY_CLOAK+1;
|
|
if (buttonMap.ButtonDown(gamefunc_NightVision))
|
|
inv_hotkey = INVENTORY_NIGHT_VISION+1;
|
|
if (buttonMap.ButtonDown(gamefunc_Gas_Bomb))
|
|
inv_hotkey = INVENTORY_CHEMBOMB+1;
|
|
if (buttonMap.ButtonDown(gamefunc_Flash_Bomb) && dimensionmode == 3)
|
|
inv_hotkey = INVENTORY_FLASHBOMB+1;
|
|
if (buttonMap.ButtonDown(gamefunc_Caltrops))
|
|
inv_hotkey = INVENTORY_CALTROPS+1;
|
|
|
|
SET(loc->bits, inv_hotkey<<SK_INV_HOTKEY_BIT0);
|
|
|
|
SET_LOC_KEY(loc->bits, SK_INV_USE, buttonMap.ButtonDown(gamefunc_Inventory));
|
|
|
|
SET_LOC_KEY(loc->bits, SK_OPERATE, buttonMap.ButtonDown(gamefunc_Open));
|
|
SET_LOC_KEY(loc->bits, SK_JUMP, buttonMap.ButtonDown(gamefunc_Jump));
|
|
SET_LOC_KEY(loc->bits, SK_CRAWL, buttonMap.ButtonDown(gamefunc_Crouch));
|
|
|
|
SET_LOC_KEY(loc->bits, SK_TURN_180, buttonMap.ButtonDown(gamefunc_TurnAround));
|
|
|
|
SET_LOC_KEY(loc->bits, SK_INV_LEFT, buttonMap.ButtonDown(gamefunc_Inventory_Left));
|
|
SET_LOC_KEY(loc->bits, SK_INV_RIGHT, buttonMap.ButtonDown(gamefunc_Inventory_Right));
|
|
|
|
SET_LOC_KEY(loc->bits, SK_HIDE_WEAPON, buttonMap.ButtonDown(gamefunc_Holster_Weapon));
|
|
|
|
// need BUTTON
|
|
SET_LOC_KEY(loc->bits, SK_CRAWL_LOCK, buttonMap.ButtonDown(gamefunc_Toggle_Crouch));
|
|
|
|
if (gNet.MultiGameType == MULTI_GAME_COOPERATIVE)
|
|
{
|
|
if (buttonMap.ButtonDown(gamefunc_See_Coop_View))
|
|
{
|
|
buttonMap.ClearButton(gamefunc_See_Coop_View);
|
|
|
|
screenpeek = connectpoint2[screenpeek];
|
|
|
|
if (screenpeek < 0)
|
|
screenpeek = connecthead;
|
|
|
|
if (dimensionmode != 2 && screenpeek == myconnectindex)
|
|
{
|
|
// JBF: figure out what's going on here
|
|
DoPlayerDivePalette(pp); // Check Dive again
|
|
DoPlayerNightVisionPalette(pp); // Check Night Vision again
|
|
}
|
|
else
|
|
{
|
|
PLAYERp tp = Player+screenpeek;
|
|
DoPlayerDivePalette(tp);
|
|
DoPlayerNightVisionPalette(tp);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DEBUG
|
|
DebugKeys(pp);
|
|
|
|
if (!CommEnabled) // Single player only keys
|
|
SinglePlayInput(pp);
|
|
#endif
|
|
|
|
if (!tied)
|
|
FunctionKeys(pp);
|
|
|
|
if (buttonMap.ButtonDown(gamefunc_Toggle_Crosshair))
|
|
{
|
|
buttonMap.ClearButton(gamefunc_Toggle_Crosshair);
|
|
pToggleCrosshair();
|
|
}
|
|
}
|
|
|
|
#define MAP_WHITE_SECTOR (LT_GREY + 2)
|
|
#define MAP_RED_SECTOR (RED + 6)
|
|
#define MAP_FLOOR_SPRITE (RED + 8)
|
|
#define MAP_ENEMY (RED + 10)
|
|
#define MAP_SPRITE (FIRE + 8)
|
|
#define MAP_PLAYER (GREEN + 6)
|
|
|
|
#define MAP_BLOCK_SPRITE (DK_BLUE + 6)
|
|
|
|
void drawoverheadmap(int cposx, int cposy, int czoom, short cang)
|
|
{
|
|
int i, j, k, l, x1, y1, x2, y2, x3, y3, x4, y4, ox, oy, xoff, yoff;
|
|
int dax, day, cosang, sinang, xspan, yspan, sprx, spry;
|
|
int xrepeat, yrepeat, z1, z2, startwall, endwall, tilenum, daang;
|
|
int xvect, yvect, xvect2, yvect2;
|
|
char col;
|
|
walltype *wal, *wal2;
|
|
spritetype *spr;
|
|
short p;
|
|
static int pspr_ndx[8]= {0,0,0,0,0,0,0,0};
|
|
SWBOOL sprisplayer = FALSE;
|
|
short txt_x, txt_y;
|
|
|
|
int32_t tmpydim = (xdim * 5) / 8;
|
|
renderSetAspect(65536, divscale16(tmpydim * 320, xdim * 200));
|
|
|
|
// draw location text
|
|
if (gs.BorderNum <= BORDER_BAR-1)
|
|
{
|
|
txt_x = 7;
|
|
txt_y = 168;
|
|
}
|
|
else
|
|
{
|
|
txt_x = 7;
|
|
txt_y = 147;
|
|
}
|
|
|
|
if (ScrollMode2D)
|
|
{
|
|
minigametext(txt_x,txt_y-7,"Follow Mode",2+8);
|
|
}
|
|
|
|
sprintf(ds,"%s",currentLevel->DisplayName());
|
|
|
|
minigametext(txt_x,txt_y,ds,2+8);
|
|
|
|
//////////////////////////////////
|
|
|
|
xvect = sintable[(2048 - cang) & 2047] * czoom;
|
|
yvect = sintable[(1536 - cang) & 2047] * czoom;
|
|
xvect2 = mulscale16(xvect, yxaspect);
|
|
yvect2 = mulscale16(yvect, yxaspect);
|
|
|
|
// Draw red lines
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
startwall = sector[i].wallptr;
|
|
endwall = sector[i].wallptr + sector[i].wallnum - 1;
|
|
|
|
z1 = sector[i].ceilingz;
|
|
z2 = sector[i].floorz;
|
|
|
|
for (j = startwall, wal = &wall[startwall]; j <= endwall; j++, wal++)
|
|
{
|
|
k = wal->nextwall;
|
|
if ((unsigned)k >= MAXWALLS)
|
|
continue;
|
|
|
|
if (!mapcheat)
|
|
{
|
|
if ((show2dwall[j >> 3] & (1 << (j & 7))) == 0)
|
|
continue;
|
|
if ((k > j) && ((show2dwall[k >> 3] & (1 << (k & 7))) > 0))
|
|
continue;
|
|
}
|
|
|
|
if (sector[wal->nextsector].ceilingz == z1)
|
|
if (sector[wal->nextsector].floorz == z2)
|
|
if (((wal->cstat | wall[wal->nextwall].cstat) & (16 + 32)) == 0)
|
|
continue;
|
|
|
|
col = 152;
|
|
|
|
//if (dimensionmode == 2)
|
|
if (dimensionmode == 6)
|
|
{
|
|
if (sector[i].floorz != sector[i].ceilingz)
|
|
if (sector[wal->nextsector].floorz != sector[wal->nextsector].ceilingz)
|
|
if (((wal->cstat | wall[wal->nextwall].cstat) & (16 + 32)) == 0)
|
|
if (sector[i].floorz == sector[wal->nextsector].floorz)
|
|
continue;
|
|
if (sector[i].floorpicnum != sector[wal->nextsector].floorpicnum)
|
|
continue;
|
|
if (sector[i].floorshade != sector[wal->nextsector].floorshade)
|
|
continue;
|
|
col = 12; // 1=white / 31=black / 44=green / 56=pink / 128=yellow / 210=blue / 248=orange / 255=purple
|
|
}
|
|
|
|
ox = wal->x - cposx;
|
|
oy = wal->y - cposy;
|
|
x1 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y1 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
wal2 = &wall[wal->point2];
|
|
ox = wal2->x - cposx;
|
|
oy = wal2->y - cposy;
|
|
x2 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y2 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
renderDrawLine(x1 + (xdim << 11), y1 + (ydim << 11), x2 + (xdim << 11), y2 + (ydim << 11), col);
|
|
}
|
|
}
|
|
|
|
// Draw sprites
|
|
k = Player[screenpeek].PlayerSprite;
|
|
for (i = 0; i < numsectors; i++)
|
|
for (j = headspritesect[i]; j >= 0; j = nextspritesect[j])
|
|
{
|
|
for (p=connecthead; p >= 0; p=connectpoint2[p])
|
|
{
|
|
if (Player[p].PlayerSprite == j)
|
|
{
|
|
if (sprite[Player[p].PlayerSprite].xvel > 16)
|
|
pspr_ndx[myconnectindex] = (((int32_t) totalclock>>4)&3);
|
|
sprisplayer = TRUE;
|
|
|
|
goto SHOWSPRITE;
|
|
}
|
|
}
|
|
if (mapcheat || (show2dsprite[j >> 3] & (1 << (j & 7))) > 0)
|
|
{
|
|
SHOWSPRITE:
|
|
spr = &sprite[j];
|
|
|
|
col = 56; // 1=white / 31=black / 44=green / 56=pink / 128=yellow / 210=blue / 248=orange / 255=purple
|
|
if ((spr->cstat & 1) > 0)
|
|
col = 248;
|
|
if (j == k)
|
|
col = 31;
|
|
|
|
sprx = spr->x;
|
|
spry = spr->y;
|
|
|
|
k = spr->statnum;
|
|
if ((k >= 1) && (k <= 8) && (k != 2)) // Interpolate moving
|
|
{
|
|
sprx = sprite[j].x;
|
|
spry = sprite[j].y;
|
|
}
|
|
|
|
switch (spr->cstat & 48)
|
|
{
|
|
case 0: // Regular sprite
|
|
if (Player[p].PlayerSprite == j)
|
|
{
|
|
ox = sprx - cposx;
|
|
oy = spry - cposy;
|
|
x1 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y1 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
if (dimensionmode == 5 && (gNet.MultiGameType != MULTI_GAME_COMMBAT || j == Player[screenpeek].PlayerSprite))
|
|
{
|
|
ox = (sintable[(spr->ang + 512) & 2047] >> 7);
|
|
oy = (sintable[(spr->ang) & 2047] >> 7);
|
|
x2 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y2 = mulscale16(oy, xvect) + mulscale16(ox, yvect);
|
|
|
|
if (j == Player[screenpeek].PlayerSprite)
|
|
{
|
|
x2 = 0L;
|
|
y2 = -(czoom << 5);
|
|
}
|
|
|
|
x3 = mulscale16(x2, yxaspect);
|
|
y3 = mulscale16(y2, yxaspect);
|
|
|
|
renderDrawLine(x1 - x2 + (xdim << 11), y1 - y3 + (ydim << 11),
|
|
x1 + x2 + (xdim << 11), y1 + y3 + (ydim << 11), col);
|
|
renderDrawLine(x1 - y2 + (xdim << 11), y1 + x3 + (ydim << 11),
|
|
x1 + x2 + (xdim << 11), y1 + y3 + (ydim << 11), col);
|
|
renderDrawLine(x1 + y2 + (xdim << 11), y1 - x3 + (ydim << 11),
|
|
x1 + x2 + (xdim << 11), y1 + y3 + (ydim << 11), col);
|
|
}
|
|
else
|
|
{
|
|
if (((gotsector[i >> 3] & (1 << (i & 7))) > 0) && (czoom > 192))
|
|
{
|
|
daang = (spr->ang - cang) & 2047;
|
|
if (j == Player[screenpeek].PlayerSprite)
|
|
{
|
|
x1 = 0;
|
|
//y1 = (yxaspect << 2);
|
|
y1 = 0;
|
|
daang = 0;
|
|
}
|
|
|
|
// Special case tiles
|
|
if (spr->picnum == 3123) break;
|
|
|
|
if (sprisplayer)
|
|
{
|
|
if (gNet.MultiGameType != MULTI_GAME_COMMBAT || j == Player[screenpeek].PlayerSprite)
|
|
rotatesprite((x1 << 4) + (xdim << 15), (y1 << 4) + (ydim << 15), mulscale16(czoom * (spr->yrepeat), yxaspect), daang, 1196+pspr_ndx[myconnectindex], spr->shade, spr->pal, (spr->cstat & 2) >> 1, windowxy1.x, windowxy1.y, windowxy2.x, windowxy2.y);
|
|
}
|
|
else
|
|
rotatesprite((x1 << 4) + (xdim << 15), (y1 << 4) + (ydim << 15), mulscale16(czoom * (spr->yrepeat), yxaspect), daang, spr->picnum, spr->shade, spr->pal, (spr->cstat & 2) >> 1, windowxy1.x, windowxy1.y, windowxy2.x, windowxy2.y);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 16: // Rotated sprite
|
|
x1 = sprx;
|
|
y1 = spry;
|
|
tilenum = spr->picnum;
|
|
xoff = (int)tileLeftOffset(tilenum) + (int)spr->xoffset;
|
|
if ((spr->cstat & 4) > 0)
|
|
xoff = -xoff;
|
|
k = spr->ang;
|
|
l = spr->xrepeat;
|
|
dax = sintable[k & 2047] * l;
|
|
day = sintable[(k + 1536) & 2047] * l;
|
|
l = tilesiz[tilenum].x;
|
|
k = (l >> 1) + xoff;
|
|
x1 -= mulscale16(dax, k);
|
|
x2 = x1 + mulscale16(dax, l);
|
|
y1 -= mulscale16(day, k);
|
|
y2 = y1 + mulscale16(day, l);
|
|
|
|
ox = x1 - cposx;
|
|
oy = y1 - cposy;
|
|
x1 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y1 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
ox = x2 - cposx;
|
|
oy = y2 - cposy;
|
|
x2 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y2 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
renderDrawLine(x1 + (xdim << 11), y1 + (ydim << 11),
|
|
x2 + (xdim << 11), y2 + (ydim << 11), col);
|
|
|
|
break;
|
|
case 32: // Floor sprite
|
|
if (dimensionmode == 5)
|
|
{
|
|
tilenum = spr->picnum;
|
|
xoff = (int)tileLeftOffset(tilenum) + (int)spr->xoffset;
|
|
yoff = (int)tileTopOffset(tilenum) + (int)spr->yoffset;
|
|
if ((spr->cstat & 4) > 0)
|
|
xoff = -xoff;
|
|
if ((spr->cstat & 8) > 0)
|
|
yoff = -yoff;
|
|
|
|
k = spr->ang;
|
|
cosang = sintable[(k + 512) & 2047];
|
|
sinang = sintable[k];
|
|
xspan = tilesiz[tilenum].x;
|
|
xrepeat = spr->xrepeat;
|
|
yspan = tilesiz[tilenum].y;
|
|
yrepeat = spr->yrepeat;
|
|
|
|
dax = ((xspan >> 1) + xoff) * xrepeat;
|
|
day = ((yspan >> 1) + yoff) * yrepeat;
|
|
x1 = sprx + mulscale16(sinang, dax) + mulscale16(cosang, day);
|
|
y1 = spry + mulscale16(sinang, day) - mulscale16(cosang, dax);
|
|
l = xspan * xrepeat;
|
|
x2 = x1 - mulscale16(sinang, l);
|
|
y2 = y1 + mulscale16(cosang, l);
|
|
l = yspan * yrepeat;
|
|
k = -mulscale16(cosang, l);
|
|
x3 = x2 + k;
|
|
x4 = x1 + k;
|
|
k = -mulscale16(sinang, l);
|
|
y3 = y2 + k;
|
|
y4 = y1 + k;
|
|
|
|
ox = x1 - cposx;
|
|
oy = y1 - cposy;
|
|
x1 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y1 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
ox = x2 - cposx;
|
|
oy = y2 - cposy;
|
|
x2 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y2 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
ox = x3 - cposx;
|
|
oy = y3 - cposy;
|
|
x3 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y3 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
ox = x4 - cposx;
|
|
oy = y4 - cposy;
|
|
x4 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y4 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
renderDrawLine(x1 + (xdim << 11), y1 + (ydim << 11),
|
|
x2 + (xdim << 11), y2 + (ydim << 11), col);
|
|
|
|
renderDrawLine(x2 + (xdim << 11), y2 + (ydim << 11),
|
|
x3 + (xdim << 11), y3 + (ydim << 11), col);
|
|
|
|
renderDrawLine(x3 + (xdim << 11), y3 + (ydim << 11),
|
|
x4 + (xdim << 11), y4 + (ydim << 11), col);
|
|
|
|
renderDrawLine(x4 + (xdim << 11), y4 + (ydim << 11),
|
|
x1 + (xdim << 11), y1 + (ydim << 11), col);
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Draw white lines
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
startwall = sector[i].wallptr;
|
|
endwall = sector[i].wallptr + sector[i].wallnum - 1;
|
|
|
|
for (j = startwall, wal = &wall[startwall]; j <= endwall; j++, wal++)
|
|
{
|
|
if ((uint16_t)wal->nextwall < MAXWALLS)
|
|
continue;
|
|
|
|
if (!mapcheat && (show2dwall[j >> 3] & (1 << (j & 7))) == 0)
|
|
continue;
|
|
|
|
if (!tileGetTexture(wal->picnum)->isValid()) continue;
|
|
|
|
ox = wal->x - cposx;
|
|
oy = wal->y - cposy;
|
|
x1 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y1 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
wal2 = &wall[wal->point2];
|
|
ox = wal2->x - cposx;
|
|
oy = wal2->y - cposy;
|
|
x2 = mulscale16(ox, xvect) - mulscale16(oy, yvect);
|
|
y2 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2);
|
|
|
|
renderDrawLine(x1 + (xdim << 11), y1 + (ydim << 11), x2 + (xdim << 11), y2 + (ydim << 11), 24);
|
|
}
|
|
}
|
|
|
|
videoSetCorrectedAspect();
|
|
|
|
}
|
|
|
|
|
|
#if RANDOM_DEBUG
|
|
int RandomRange(int range, char *file, unsigned line)
|
|
{
|
|
uint32_t rand_num;
|
|
uint32_t value;
|
|
extern FILE *fout_err;
|
|
extern uint32_t MoveThingsCount;
|
|
|
|
if (RandomPrint && !Prediction)
|
|
{
|
|
sprintf(ds,"mtc %d, %s, line %d, %d",MoveThingsCount,file,line,randomseed);
|
|
DebugWriteString(ds);
|
|
}
|
|
|
|
if (range <= 0)
|
|
return 0;
|
|
|
|
rand_num = krand2();
|
|
|
|
if (rand_num == 65535U)
|
|
rand_num--;
|
|
|
|
// shift values to give more precision
|
|
value = (rand_num << 14) / ((65535UL << 14) / range);
|
|
|
|
if (value >= range)
|
|
value = range - 1;
|
|
|
|
return value;
|
|
}
|
|
#else
|
|
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) / ((65535UL << 14) / range);
|
|
|
|
if (value >= (uint32_t)range)
|
|
value = range - 1;
|
|
|
|
return value;
|
|
}
|
|
#endif
|
|
|
|
int StdRandomRange(int range)
|
|
{
|
|
uint32_t rand_num;
|
|
uint32_t value;
|
|
|
|
if (range <= 0)
|
|
return 0;
|
|
|
|
rand_num = STD_RANDOM();
|
|
|
|
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;
|
|
}
|
|
|
|
// [JM] Probably will need some doing over. !CHECKME!
|
|
void G_Polymer_UnInit(void) { }
|
|
|
|
|
|
#include "saveable.h"
|
|
|
|
saveable_module saveable_build{};
|
|
|
|
void Saveable_Init_Dynamic()
|
|
{
|
|
static saveable_data saveable_build_data[] =
|
|
{
|
|
{sector, MAXSECTORS*sizeof(sectortype)},
|
|
{sprite, MAXSPRITES*sizeof(spritetype)},
|
|
{wall, MAXWALLS*sizeof(walltype)},
|
|
};
|
|
|
|
saveable_build.data = saveable_build_data;
|
|
saveable_build.numdata = NUM_SAVEABLE_ITEMS(saveable_build_data);
|
|
}
|
|
|
|
void GameInterface::set_hud_layout(int requested_size)
|
|
{
|
|
gs.BorderNum = 9 - requested_size;
|
|
SetBorder(Player + myconnectindex);
|
|
}
|
|
|
|
::GameInterface* CreateInterface()
|
|
{
|
|
return new GameInterface;
|
|
}
|
|
|
|
|
|
GameStats GameInterface::getStats()
|
|
{
|
|
PLAYERp pp = Player + myconnectindex;
|
|
return { pp->Kills, TotalKillable, pp->SecretsFound, LevelSecrets, PlayClock / 120, 0 };
|
|
}
|
|
|
|
void GameInterface::FreeGameData()
|
|
{
|
|
TerminateLevel();
|
|
}
|
|
|
|
void GameInterface::UpdateScreenSize()
|
|
{
|
|
// Fixme. The underlying code here is too broken and must be refactored first.
|
|
}
|
|
|
|
|
|
END_SW_NS
|