Initial Checkin
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@15 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
b3fb01bfed
commit
8184225473
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
{-0.525731, 0.000000, 0.850651},
|
||||
{-0.442863, 0.238856, 0.864188},
|
||||
{-0.295242, 0.000000, 0.955423},
|
||||
{-0.309017, 0.500000, 0.809017},
|
||||
{-0.162460, 0.262866, 0.951056},
|
||||
{0.000000, 0.000000, 1.000000},
|
||||
{0.000000, 0.850651, 0.525731},
|
||||
{-0.147621, 0.716567, 0.681718},
|
||||
{0.147621, 0.716567, 0.681718},
|
||||
{0.000000, 0.525731, 0.850651},
|
||||
{0.309017, 0.500000, 0.809017},
|
||||
{0.525731, 0.000000, 0.850651},
|
||||
{0.295242, 0.000000, 0.955423},
|
||||
{0.442863, 0.238856, 0.864188},
|
||||
{0.162460, 0.262866, 0.951056},
|
||||
{-0.681718, 0.147621, 0.716567},
|
||||
{-0.809017, 0.309017, 0.500000},
|
||||
{-0.587785, 0.425325, 0.688191},
|
||||
{-0.850651, 0.525731, 0.000000},
|
||||
{-0.864188, 0.442863, 0.238856},
|
||||
{-0.716567, 0.681718, 0.147621},
|
||||
{-0.688191, 0.587785, 0.425325},
|
||||
{-0.500000, 0.809017, 0.309017},
|
||||
{-0.238856, 0.864188, 0.442863},
|
||||
{-0.425325, 0.688191, 0.587785},
|
||||
{-0.716567, 0.681718, -0.147621},
|
||||
{-0.500000, 0.809017, -0.309017},
|
||||
{-0.525731, 0.850651, 0.000000},
|
||||
{0.000000, 0.850651, -0.525731},
|
||||
{-0.238856, 0.864188, -0.442863},
|
||||
{0.000000, 0.955423, -0.295242},
|
||||
{-0.262866, 0.951056, -0.162460},
|
||||
{0.000000, 1.000000, 0.000000},
|
||||
{0.000000, 0.955423, 0.295242},
|
||||
{-0.262866, 0.951056, 0.162460},
|
||||
{0.238856, 0.864188, 0.442863},
|
||||
{0.262866, 0.951056, 0.162460},
|
||||
{0.500000, 0.809017, 0.309017},
|
||||
{0.238856, 0.864188, -0.442863},
|
||||
{0.262866, 0.951056, -0.162460},
|
||||
{0.500000, 0.809017, -0.309017},
|
||||
{0.850651, 0.525731, 0.000000},
|
||||
{0.716567, 0.681718, 0.147621},
|
||||
{0.716567, 0.681718, -0.147621},
|
||||
{0.525731, 0.850651, 0.000000},
|
||||
{0.425325, 0.688191, 0.587785},
|
||||
{0.864188, 0.442863, 0.238856},
|
||||
{0.688191, 0.587785, 0.425325},
|
||||
{0.809017, 0.309017, 0.500000},
|
||||
{0.681718, 0.147621, 0.716567},
|
||||
{0.587785, 0.425325, 0.688191},
|
||||
{0.955423, 0.295242, 0.000000},
|
||||
{1.000000, 0.000000, 0.000000},
|
||||
{0.951056, 0.162460, 0.262866},
|
||||
{0.850651, -0.525731, 0.000000},
|
||||
{0.955423, -0.295242, 0.000000},
|
||||
{0.864188, -0.442863, 0.238856},
|
||||
{0.951056, -0.162460, 0.262866},
|
||||
{0.809017, -0.309017, 0.500000},
|
||||
{0.681718, -0.147621, 0.716567},
|
||||
{0.850651, 0.000000, 0.525731},
|
||||
{0.864188, 0.442863, -0.238856},
|
||||
{0.809017, 0.309017, -0.500000},
|
||||
{0.951056, 0.162460, -0.262866},
|
||||
{0.525731, 0.000000, -0.850651},
|
||||
{0.681718, 0.147621, -0.716567},
|
||||
{0.681718, -0.147621, -0.716567},
|
||||
{0.850651, 0.000000, -0.525731},
|
||||
{0.809017, -0.309017, -0.500000},
|
||||
{0.864188, -0.442863, -0.238856},
|
||||
{0.951056, -0.162460, -0.262866},
|
||||
{0.147621, 0.716567, -0.681718},
|
||||
{0.309017, 0.500000, -0.809017},
|
||||
{0.425325, 0.688191, -0.587785},
|
||||
{0.442863, 0.238856, -0.864188},
|
||||
{0.587785, 0.425325, -0.688191},
|
||||
{0.688191, 0.587785, -0.425325},
|
||||
{-0.147621, 0.716567, -0.681718},
|
||||
{-0.309017, 0.500000, -0.809017},
|
||||
{0.000000, 0.525731, -0.850651},
|
||||
{-0.525731, 0.000000, -0.850651},
|
||||
{-0.442863, 0.238856, -0.864188},
|
||||
{-0.295242, 0.000000, -0.955423},
|
||||
{-0.162460, 0.262866, -0.951056},
|
||||
{0.000000, 0.000000, -1.000000},
|
||||
{0.295242, 0.000000, -0.955423},
|
||||
{0.162460, 0.262866, -0.951056},
|
||||
{-0.442863, -0.238856, -0.864188},
|
||||
{-0.309017, -0.500000, -0.809017},
|
||||
{-0.162460, -0.262866, -0.951056},
|
||||
{0.000000, -0.850651, -0.525731},
|
||||
{-0.147621, -0.716567, -0.681718},
|
||||
{0.147621, -0.716567, -0.681718},
|
||||
{0.000000, -0.525731, -0.850651},
|
||||
{0.309017, -0.500000, -0.809017},
|
||||
{0.442863, -0.238856, -0.864188},
|
||||
{0.162460, -0.262866, -0.951056},
|
||||
{0.238856, -0.864188, -0.442863},
|
||||
{0.500000, -0.809017, -0.309017},
|
||||
{0.425325, -0.688191, -0.587785},
|
||||
{0.716567, -0.681718, -0.147621},
|
||||
{0.688191, -0.587785, -0.425325},
|
||||
{0.587785, -0.425325, -0.688191},
|
||||
{0.000000, -0.955423, -0.295242},
|
||||
{0.000000, -1.000000, 0.000000},
|
||||
{0.262866, -0.951056, -0.162460},
|
||||
{0.000000, -0.850651, 0.525731},
|
||||
{0.000000, -0.955423, 0.295242},
|
||||
{0.238856, -0.864188, 0.442863},
|
||||
{0.262866, -0.951056, 0.162460},
|
||||
{0.500000, -0.809017, 0.309017},
|
||||
{0.716567, -0.681718, 0.147621},
|
||||
{0.525731, -0.850651, 0.000000},
|
||||
{-0.238856, -0.864188, -0.442863},
|
||||
{-0.500000, -0.809017, -0.309017},
|
||||
{-0.262866, -0.951056, -0.162460},
|
||||
{-0.850651, -0.525731, 0.000000},
|
||||
{-0.716567, -0.681718, -0.147621},
|
||||
{-0.716567, -0.681718, 0.147621},
|
||||
{-0.525731, -0.850651, 0.000000},
|
||||
{-0.500000, -0.809017, 0.309017},
|
||||
{-0.238856, -0.864188, 0.442863},
|
||||
{-0.262866, -0.951056, 0.162460},
|
||||
{-0.864188, -0.442863, 0.238856},
|
||||
{-0.809017, -0.309017, 0.500000},
|
||||
{-0.688191, -0.587785, 0.425325},
|
||||
{-0.681718, -0.147621, 0.716567},
|
||||
{-0.442863, -0.238856, 0.864188},
|
||||
{-0.587785, -0.425325, 0.688191},
|
||||
{-0.309017, -0.500000, 0.809017},
|
||||
{-0.147621, -0.716567, 0.681718},
|
||||
{-0.425325, -0.688191, 0.587785},
|
||||
{-0.162460, -0.262866, 0.951056},
|
||||
{0.442863, -0.238856, 0.864188},
|
||||
{0.162460, -0.262866, 0.951056},
|
||||
{0.309017, -0.500000, 0.809017},
|
||||
{0.147621, -0.716567, 0.681718},
|
||||
{0.000000, -0.525731, 0.850651},
|
||||
{0.425325, -0.688191, 0.587785},
|
||||
{0.587785, -0.425325, 0.688191},
|
||||
{0.688191, -0.587785, 0.425325},
|
||||
{-0.955423, 0.295242, 0.000000},
|
||||
{-0.951056, 0.162460, 0.262866},
|
||||
{-1.000000, 0.000000, 0.000000},
|
||||
{-0.850651, 0.000000, 0.525731},
|
||||
{-0.955423, -0.295242, 0.000000},
|
||||
{-0.951056, -0.162460, 0.262866},
|
||||
{-0.864188, 0.442863, -0.238856},
|
||||
{-0.951056, 0.162460, -0.262866},
|
||||
{-0.809017, 0.309017, -0.500000},
|
||||
{-0.864188, -0.442863, -0.238856},
|
||||
{-0.951056, -0.162460, -0.262866},
|
||||
{-0.809017, -0.309017, -0.500000},
|
||||
{-0.681718, 0.147621, -0.716567},
|
||||
{-0.681718, -0.147621, -0.716567},
|
||||
{-0.850651, 0.000000, -0.525731},
|
||||
{-0.688191, 0.587785, -0.425325},
|
||||
{-0.587785, 0.425325, -0.688191},
|
||||
{-0.425325, 0.688191, -0.587785},
|
||||
{-0.425325, -0.688191, -0.587785},
|
||||
{-0.587785, -0.425325, -0.688191},
|
||||
{-0.688191, -0.587785, -0.425325},
|
|
@ -0,0 +1,481 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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 included (GNU.txt) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
|
||||
// rights reserved.
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
|
||||
extern HWND mainwindow;
|
||||
extern cvar_t bgmvolume;
|
||||
|
||||
static qboolean cdValid = false;
|
||||
static qboolean playing = false;
|
||||
static qboolean wasPlaying = false;
|
||||
static qboolean initialized = false;
|
||||
static qboolean enabled = false;
|
||||
static qboolean playLooping = false;
|
||||
static float cdvolume;
|
||||
static qbyte remap[100];
|
||||
static qbyte cdrom;
|
||||
static qbyte playTrack;
|
||||
static qbyte maxTrack;
|
||||
|
||||
static qboolean playingsoundfile;
|
||||
|
||||
UINT wDeviceID;
|
||||
|
||||
|
||||
static void CDAudio_Eject(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
|
||||
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD)NULL))
|
||||
Con_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", dwReturn);
|
||||
}
|
||||
|
||||
|
||||
static void CDAudio_CloseDoor(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
|
||||
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD)NULL))
|
||||
Con_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", dwReturn);
|
||||
}
|
||||
|
||||
|
||||
static int CDAudio_GetAudioDiskInfo(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_STATUS_PARMS mciStatusParms;
|
||||
|
||||
|
||||
cdValid = false;
|
||||
|
||||
mciStatusParms.dwItem = MCI_STATUS_READY;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Con_DPrintf("CDAudio: drive ready test - get status failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (!mciStatusParms.dwReturn)
|
||||
{
|
||||
Con_DPrintf("CDAudio: drive not ready\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Con_DPrintf("CDAudio: get tracks - status failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (mciStatusParms.dwReturn < 1)
|
||||
{
|
||||
Con_DPrintf("CDAudio: no music tracks\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cdValid = true;
|
||||
maxTrack = mciStatusParms.dwReturn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Play(int track, qboolean looping)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_PLAY_PARMS mciPlayParms;
|
||||
MCI_STATUS_PARMS mciStatusParms;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!cdValid)
|
||||
{
|
||||
CDAudio_GetAudioDiskInfo();
|
||||
if (!cdValid)
|
||||
return;
|
||||
}
|
||||
|
||||
track = remap[track];
|
||||
|
||||
if (track < 1 || track > maxTrack)
|
||||
{
|
||||
Con_DPrintf("CDAudio: Bad track number %u.\n", track);
|
||||
return;
|
||||
}
|
||||
|
||||
// don't try to play a non-audio track
|
||||
mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
|
||||
mciStatusParms.dwTrack = track;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
|
||||
return;
|
||||
}
|
||||
if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO)
|
||||
{
|
||||
Con_Printf("CDAudio: track %i is not audio\n", track);
|
||||
return;
|
||||
}
|
||||
|
||||
// get the length of the track to be played
|
||||
mciStatusParms.dwItem = MCI_STATUS_LENGTH;
|
||||
mciStatusParms.dwTrack = track;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (playing)
|
||||
{
|
||||
if (playTrack == track)
|
||||
return;
|
||||
CDAudio_Stop();
|
||||
}
|
||||
|
||||
mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0);
|
||||
mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track;
|
||||
mciPlayParms.dwCallback = (DWORD)mainwindow;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Con_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
|
||||
return;
|
||||
}
|
||||
|
||||
playLooping = looping;
|
||||
playTrack = track;
|
||||
playing = true;
|
||||
|
||||
if (cdvolume == 0.0)
|
||||
CDAudio_Pause ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Stop(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!playing)
|
||||
return;
|
||||
|
||||
if ((dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD)NULL)))
|
||||
Con_DPrintf("MCI_STOP failed (%i)", dwReturn);
|
||||
|
||||
wasPlaying = false;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Pause(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_GENERIC_PARMS mciGenericParms;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!playing)
|
||||
return;
|
||||
|
||||
mciGenericParms.dwCallback = (DWORD)mainwindow;
|
||||
if ((dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &mciGenericParms)))
|
||||
Con_DPrintf("MCI_PAUSE failed (%i)", dwReturn);
|
||||
|
||||
wasPlaying = playing;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Resume(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_PLAY_PARMS mciPlayParms;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!cdValid)
|
||||
return;
|
||||
|
||||
if (!wasPlaying)
|
||||
return;
|
||||
|
||||
mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0);
|
||||
mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0);
|
||||
mciPlayParms.dwCallback = (DWORD)mainwindow;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Con_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
|
||||
return;
|
||||
}
|
||||
playing = true;
|
||||
}
|
||||
|
||||
|
||||
static void CD_f (void)
|
||||
{
|
||||
char *command;
|
||||
int ret;
|
||||
int n;
|
||||
|
||||
if (Cmd_Argc() < 2)
|
||||
return;
|
||||
|
||||
command = Cmd_Argv (1);
|
||||
|
||||
if (Q_strcasecmp(command, "on") == 0)
|
||||
{
|
||||
enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "off") == 0)
|
||||
{
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "reset") == 0)
|
||||
{
|
||||
enabled = true;
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
for (n = 0; n < 100; n++)
|
||||
remap[n] = n;
|
||||
CDAudio_GetAudioDiskInfo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "remap") == 0)
|
||||
{
|
||||
ret = Cmd_Argc() - 2;
|
||||
if (ret <= 0)
|
||||
{
|
||||
for (n = 1; n < 100; n++)
|
||||
if (remap[n] != n)
|
||||
Con_Printf(" %u -> %u\n", n, remap[n]);
|
||||
return;
|
||||
}
|
||||
for (n = 1; n <= ret; n++)
|
||||
remap[n] = Q_atoi(Cmd_Argv (n+1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "close") == 0)
|
||||
{
|
||||
CDAudio_CloseDoor();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "play") == 0)
|
||||
{
|
||||
CDAudio_Play((qbyte)Q_atoi(Cmd_Argv (2)), false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cdValid)
|
||||
{
|
||||
CDAudio_GetAudioDiskInfo();
|
||||
if (!cdValid)
|
||||
{
|
||||
Con_Printf("No CD in player.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "loop") == 0)
|
||||
{
|
||||
CDAudio_Play((qbyte)Q_atoi(Cmd_Argv (2)), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "stop") == 0)
|
||||
{
|
||||
CDAudio_Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "pause") == 0)
|
||||
{
|
||||
CDAudio_Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "resume") == 0)
|
||||
{
|
||||
CDAudio_Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "eject") == 0)
|
||||
{
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
CDAudio_Eject();
|
||||
cdValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "info") == 0)
|
||||
{
|
||||
Con_Printf("%u tracks\n", maxTrack);
|
||||
if (playing)
|
||||
Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
|
||||
else if (wasPlaying)
|
||||
Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
|
||||
Con_Printf("Volume is %f\n", cdvolume);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (lParam != wDeviceID)
|
||||
return 1;
|
||||
|
||||
switch (wParam)
|
||||
{
|
||||
case MCI_NOTIFY_SUCCESSFUL:
|
||||
if (playing)
|
||||
{
|
||||
playing = false;
|
||||
if (playLooping)
|
||||
CDAudio_Play(playTrack, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case MCI_NOTIFY_ABORTED:
|
||||
case MCI_NOTIFY_SUPERSEDED:
|
||||
break;
|
||||
|
||||
case MCI_NOTIFY_FAILURE:
|
||||
Con_DPrintf("MCI_NOTIFY_FAILURE\n");
|
||||
CDAudio_Stop ();
|
||||
cdValid = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
Con_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Update(void)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (bgmvolume.value != cdvolume)
|
||||
{
|
||||
if (cdvolume)
|
||||
{
|
||||
Cvar_SetValue (&bgmvolume, 0.0);
|
||||
cdvolume = bgmvolume.value;
|
||||
CDAudio_Pause ();
|
||||
}
|
||||
else
|
||||
{
|
||||
Cvar_SetValue (&bgmvolume, 1.0);
|
||||
cdvolume = bgmvolume.value;
|
||||
CDAudio_Resume ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CDAudio_Init(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_OPEN_PARMS mciOpenParms;
|
||||
MCI_SET_PARMS mciSetParms;
|
||||
int n;
|
||||
|
||||
#if 0 // QW
|
||||
if (cls.state == ca_dedicated)
|
||||
return -1;
|
||||
#endif
|
||||
if (COM_CheckParm("-nocdaudio"))
|
||||
return -1;
|
||||
|
||||
mciOpenParms.lpstrDeviceType = "cdaudio";
|
||||
if ((dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD) (LPVOID) &mciOpenParms)))
|
||||
{
|
||||
Con_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", dwReturn);
|
||||
return -1;
|
||||
}
|
||||
wDeviceID = mciOpenParms.wDeviceID;
|
||||
|
||||
// Set the time format to track/minute/second/frame (TMSF).
|
||||
mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
|
||||
if ((dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms)))
|
||||
{
|
||||
Con_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", dwReturn);
|
||||
mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < 100; n++)
|
||||
remap[n] = n;
|
||||
initialized = true;
|
||||
enabled = true;
|
||||
|
||||
if (CDAudio_GetAudioDiskInfo())
|
||||
{
|
||||
Con_Printf("CDAudio_Init: No CD in player.\n");
|
||||
cdValid = false;
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
Cmd_AddCommand ("cd", CD_f);
|
||||
|
||||
// Con_Printf("CD Audio Initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Shutdown(void)
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
CDAudio_Stop();
|
||||
if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL))
|
||||
Con_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
int CDAudio_Init(void);
|
||||
void CDAudio_Play(int track, qboolean looping);
|
||||
void CDAudio_Stop(void);
|
||||
void CDAudio_Pause(void);
|
||||
void CDAudio_Resume(void);
|
||||
void CDAudio_Shutdown(void);
|
||||
void CDAudio_Update(void);
|
||||
|
||||
void CDAudio_TrackEnded(void);
|
||||
|
||||
|
|
@ -0,0 +1,527 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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 included (GNU.txt) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
/* ZOID
|
||||
*
|
||||
* Player camera tracking in Spectator mode
|
||||
*
|
||||
* This takes over player controls for spectator automatic camera.
|
||||
* Player moves as a spectator, but the camera tracks and enemy player
|
||||
*/
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
|
||||
#define PM_SPECTATORMAXSPEED 500
|
||||
#define PM_STOPSPEED 100
|
||||
#define PM_MAXSPEED 320
|
||||
#define BUTTON_JUMP 2
|
||||
#define BUTTON_ATTACK 1
|
||||
#define MAX_ANGLE_TURN 10
|
||||
|
||||
static vec3_t desired_position[MAX_SPLITS]; // where the camera wants to be
|
||||
static qboolean locked[MAX_SPLITS];
|
||||
static int oldbuttons[MAX_SPLITS];
|
||||
|
||||
char cl_spectatorgroup[] = "Spectator Tracking";
|
||||
|
||||
// track high fragger
|
||||
cvar_t cl_hightrack = {"cl_hightrack", "0" };
|
||||
|
||||
cvar_t cl_chasecam = {"cl_chasecam", "0"};
|
||||
|
||||
//cvar_t cl_camera_maxpitch = {"cl_camera_maxpitch", "10" };
|
||||
//cvar_t cl_camera_maxyaw = {"cl_camera_maxyaw", "30" };
|
||||
|
||||
qboolean cam_forceview[MAX_SPLITS];
|
||||
vec3_t cam_viewangles[MAX_SPLITS];
|
||||
double cam_lastviewtime[MAX_SPLITS];
|
||||
|
||||
int spec_track[MAX_SPLITS]; // player# of who we are tracking
|
||||
int autocam[MAX_SPLITS];
|
||||
|
||||
void vectoangles(vec3_t vec, vec3_t ang)
|
||||
{
|
||||
float forward;
|
||||
float yaw, pitch;
|
||||
|
||||
if (vec[1] == 0 && vec[0] == 0)
|
||||
{
|
||||
yaw = 0;
|
||||
if (vec[2] > 0)
|
||||
pitch = 90;
|
||||
else
|
||||
pitch = 270;
|
||||
}
|
||||
else
|
||||
{
|
||||
yaw = (int) (atan2(vec[1], vec[0]) * 180 / M_PI);
|
||||
if (yaw < 0)
|
||||
yaw += 360;
|
||||
|
||||
forward = sqrt (vec[0]*vec[0] + vec[1]*vec[1]);
|
||||
pitch = (int) (atan2(vec[2], forward) * 180 / M_PI);
|
||||
if (pitch < 0)
|
||||
pitch += 360;
|
||||
}
|
||||
|
||||
ang[0] = pitch;
|
||||
ang[1] = yaw;
|
||||
ang[2] = 0;
|
||||
}
|
||||
|
||||
static float vlen(vec3_t v)
|
||||
{
|
||||
return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||
}
|
||||
|
||||
// returns true if weapon model should be drawn in camera mode
|
||||
qboolean Cam_DrawViewModel(int pnum)
|
||||
{
|
||||
if (!cl.spectator)
|
||||
return true;
|
||||
|
||||
if (autocam[pnum] && locked[pnum] && cl_chasecam.value)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns true if we should draw this player, we don't if we are chase camming
|
||||
qboolean Cam_DrawPlayer(int pnum, int playernum)
|
||||
{
|
||||
if (cl.spectator && autocam[pnum] && locked[pnum] && cl_chasecam.value &&
|
||||
spec_track[pnum] == playernum)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cam_Unlock(int pnum)
|
||||
{
|
||||
if (autocam[pnum])
|
||||
{
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
MSG_WriteString (&cls.netchan.message, "ptrack");
|
||||
autocam[pnum] = CAM_NONE;
|
||||
locked[pnum] = false;
|
||||
Sbar_Changed();
|
||||
}
|
||||
}
|
||||
|
||||
void Cam_Lock(int pnum, int playernum)
|
||||
{
|
||||
char st[40];
|
||||
|
||||
sprintf(st, "ptrack %i", playernum);
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
MSG_WriteString (&cls.netchan.message, st);
|
||||
spec_track[pnum] = playernum;
|
||||
cam_forceview[pnum] = true;
|
||||
locked[pnum] = false;
|
||||
Sbar_Changed();
|
||||
}
|
||||
|
||||
trace_t Cam_DoTrace(vec3_t vec1, vec3_t vec2)
|
||||
{
|
||||
#if 0
|
||||
memset(&pmove, 0, sizeof(pmove));
|
||||
|
||||
pmove.numphysent = 1;
|
||||
VectorCopy (vec3_origin, pmove.physents[0].origin);
|
||||
pmove.physents[0].model = cl.worldmodel;
|
||||
#endif
|
||||
|
||||
VectorCopy (vec1, pmove.origin);
|
||||
return PM_PlayerTrace(pmove.origin, vec2);
|
||||
}
|
||||
|
||||
// Returns distance or 9999 if invalid for some reason
|
||||
static float Cam_TryFlyby(player_state_t *self, player_state_t *player, vec3_t vec, qboolean checkvis)
|
||||
{
|
||||
vec3_t v;
|
||||
trace_t trace;
|
||||
float len;
|
||||
|
||||
vectoangles(vec, v);
|
||||
// v[0] = -v[0];
|
||||
VectorCopy (v, pmove.angles);
|
||||
VectorNormalize(vec);
|
||||
VectorMA(player->origin, 800, vec, v);
|
||||
// v is endpos
|
||||
// fake a player move
|
||||
trace = Cam_DoTrace(player->origin, v);
|
||||
if (/*trace.inopen ||*/ trace.inwater)
|
||||
return 9999;
|
||||
VectorCopy(trace.endpos, vec);
|
||||
VectorSubtract(trace.endpos, player->origin, v);
|
||||
len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||
if (len < 32 || len > 800)
|
||||
return 9999;
|
||||
if (checkvis)
|
||||
{
|
||||
VectorSubtract(trace.endpos, self->origin, v);
|
||||
len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||
|
||||
trace = Cam_DoTrace(self->origin, vec);
|
||||
if (trace.fraction != 1 || trace.inwater)
|
||||
return 9999;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// Is player visible?
|
||||
static qboolean Cam_IsVisible(player_state_t *player, vec3_t vec)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t v;
|
||||
float d;
|
||||
|
||||
trace = Cam_DoTrace(player->origin, vec);
|
||||
if (trace.fraction != 1 || /*trace.inopen ||*/ trace.inwater)
|
||||
return false;
|
||||
// check distance, don't let the player get too far away or too close
|
||||
VectorSubtract(player->origin, vec, v);
|
||||
d = vlen(v);
|
||||
if (d < 16)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static qboolean InitFlyby(int pnum, player_state_t *self, player_state_t *player, int checkvis)
|
||||
{
|
||||
float f, max;
|
||||
vec3_t vec, vec2;
|
||||
vec3_t forward, right, up;
|
||||
|
||||
VectorCopy(player->viewangles, vec);
|
||||
vec[0] = 0;
|
||||
AngleVectors (vec, forward, right, up);
|
||||
// for (i = 0; i < 3; i++)
|
||||
// forward[i] *= 3;
|
||||
|
||||
max = 1000;
|
||||
VectorAdd(forward, up, vec2);
|
||||
VectorAdd(vec2, right, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorAdd(forward, up, vec2);
|
||||
VectorSubtract(vec2, right, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorAdd(forward, right, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorSubtract(forward, right, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorAdd(forward, up, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorSubtract(forward, up, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorAdd(up, right, vec2);
|
||||
VectorSubtract(vec2, forward, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorSubtract(up, right, vec2);
|
||||
VectorSubtract(vec2, forward, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
// invert
|
||||
VectorSubtract(vec3_origin, forward, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorCopy(forward, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
// invert
|
||||
VectorSubtract(vec3_origin, right, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
VectorCopy(right, vec2);
|
||||
if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max)
|
||||
{
|
||||
max = f;
|
||||
VectorCopy(vec2, vec);
|
||||
}
|
||||
|
||||
// ack, can't find him
|
||||
if (max >= 1000)
|
||||
{
|
||||
// Cam_Unlock();
|
||||
return false;
|
||||
}
|
||||
locked[pnum] = true;
|
||||
VectorCopy(vec, desired_position[pnum]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Cam_CheckHighTarget(int pnum)
|
||||
{
|
||||
int i, j, max;
|
||||
player_info_t *s;
|
||||
|
||||
j = -1;
|
||||
for (i = 0, max = -9999; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
s = &cl.players[i];
|
||||
if (s->name[0] && !s->spectator && s->frags > max)
|
||||
{
|
||||
max = s->frags;
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
if (j >= 0)
|
||||
{
|
||||
if (!locked[pnum] || cl.players[j].frags > cl.players[spec_track[pnum]].frags)
|
||||
Cam_Lock(pnum, j);
|
||||
}
|
||||
else
|
||||
Cam_Unlock(pnum);
|
||||
}
|
||||
|
||||
// ZOID
|
||||
//
|
||||
// Take over the user controls and track a player.
|
||||
// We find a nice position to watch the player and move there
|
||||
void Cam_Track(int pnum, usercmd_t *cmd)
|
||||
{
|
||||
player_state_t *player, *self;
|
||||
frame_t *frame;
|
||||
vec3_t vec;
|
||||
float len;
|
||||
|
||||
if (!cl.spectator)
|
||||
return;
|
||||
|
||||
if (cl_hightrack.value && !locked[pnum])
|
||||
Cam_CheckHighTarget(pnum);
|
||||
|
||||
if (!autocam[pnum] || cls.state != ca_active)
|
||||
return;
|
||||
|
||||
if (locked[pnum] && (!cl.players[spec_track[pnum]].name[0] || cl.players[spec_track[pnum]].spectator))
|
||||
{
|
||||
locked[pnum] = false;
|
||||
if (cl_hightrack.value)
|
||||
Cam_CheckHighTarget(pnum);
|
||||
else
|
||||
Cam_Unlock(pnum);
|
||||
return;
|
||||
}
|
||||
|
||||
frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
|
||||
player = frame->playerstate + spec_track[pnum];
|
||||
self = frame->playerstate + cl.playernum[pnum];
|
||||
|
||||
if (locked[pnum] || !Cam_IsVisible(player, desired_position[pnum]))
|
||||
{
|
||||
if (!locked[pnum] || realtime - cam_lastviewtime[pnum] > 0.1)
|
||||
{
|
||||
if (!InitFlyby(pnum, self, player, true))
|
||||
InitFlyby(pnum, self, player, false);
|
||||
cam_lastviewtime[pnum] = realtime;
|
||||
}
|
||||
}
|
||||
else
|
||||
cam_lastviewtime[pnum] = realtime;
|
||||
|
||||
// couldn't track for some reason
|
||||
if (!locked[pnum] || !autocam[pnum])
|
||||
return;
|
||||
|
||||
if (cl_chasecam.value)
|
||||
{
|
||||
cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
|
||||
|
||||
VectorCopy(player->viewangles, cl.viewangles[pnum]);
|
||||
VectorCopy(player->origin, desired_position[pnum]);
|
||||
if (memcmp(&desired_position[pnum], &self->origin, sizeof(desired_position[pnum])) != 0)
|
||||
{
|
||||
MSG_WriteByte (&cls.netchan.message, clc_tmove);
|
||||
MSG_WriteCoord (&cls.netchan.message, desired_position[pnum][0]);
|
||||
MSG_WriteCoord (&cls.netchan.message, desired_position[pnum][1]);
|
||||
MSG_WriteCoord (&cls.netchan.message, desired_position[pnum][2]);
|
||||
// move there locally immediately
|
||||
VectorCopy(desired_position[pnum], self->origin);
|
||||
}
|
||||
self->weaponframe = player->weaponframe;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ok, move to our desired position and set our angles to view
|
||||
// the player
|
||||
VectorSubtract(desired_position[pnum], self->origin, vec);
|
||||
len = vlen(vec);
|
||||
cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
|
||||
if (len > 16)
|
||||
{ // close enough?
|
||||
MSG_WriteByte (&cls.netchan.message, clc_tmove);
|
||||
MSG_WriteCoord (&cls.netchan.message, desired_position[pnum][0]);
|
||||
MSG_WriteCoord (&cls.netchan.message, desired_position[pnum][1]);
|
||||
MSG_WriteCoord (&cls.netchan.message, desired_position[pnum][2]);
|
||||
}
|
||||
|
||||
// move there locally immediately
|
||||
VectorCopy(desired_position[pnum], self->origin);
|
||||
|
||||
VectorSubtract(player->origin, desired_position[pnum], vec);
|
||||
vectoangles(vec, cl.viewangles[pnum]);
|
||||
cl.viewangles[pnum][0] = -cl.viewangles[pnum][0];
|
||||
}
|
||||
}
|
||||
|
||||
void Cam_FinishMove(int pnum, usercmd_t *cmd)
|
||||
{
|
||||
int i;
|
||||
player_info_t *s;
|
||||
int end;
|
||||
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
if (!cl.spectator) // only in spectator mode
|
||||
return;
|
||||
|
||||
if (cmd->buttons & BUTTON_ATTACK)
|
||||
{
|
||||
if (!(oldbuttons[pnum] & BUTTON_ATTACK))
|
||||
{
|
||||
|
||||
oldbuttons[pnum] |= BUTTON_ATTACK;
|
||||
autocam[pnum]++;
|
||||
|
||||
if (autocam[pnum] > CAM_TRACK)
|
||||
{
|
||||
Cam_Unlock(pnum);
|
||||
VectorCopy(cl.viewangles[pnum], cmd->angles);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldbuttons[pnum] &= ~BUTTON_ATTACK;
|
||||
if (!autocam[pnum])
|
||||
return;
|
||||
}
|
||||
|
||||
if (autocam[pnum] && cl_hightrack.value)
|
||||
{
|
||||
Cam_CheckHighTarget(pnum);
|
||||
return;
|
||||
}
|
||||
|
||||
if (locked[pnum])
|
||||
{
|
||||
if ((cmd->buttons & BUTTON_JUMP) && (oldbuttons[pnum] & BUTTON_JUMP))
|
||||
return; // don't pogo stick
|
||||
|
||||
if (!(cmd->buttons & BUTTON_JUMP))
|
||||
{
|
||||
oldbuttons[pnum] &= ~BUTTON_JUMP;
|
||||
return;
|
||||
}
|
||||
oldbuttons[pnum] |= BUTTON_JUMP; // don't jump again until released
|
||||
}
|
||||
|
||||
// Con_Printf("Selecting track target...\n");
|
||||
|
||||
if (locked[pnum] && autocam[pnum])
|
||||
end = (spec_track[pnum] + 1) % MAX_CLIENTS;
|
||||
else
|
||||
end = spec_track[pnum];
|
||||
i = end;
|
||||
do
|
||||
{
|
||||
s = &cl.players[i];
|
||||
if (s->name[0] && !s->spectator)
|
||||
{
|
||||
Cam_Lock(pnum, i);
|
||||
return;
|
||||
}
|
||||
i = (i + 1) % MAX_CLIENTS;
|
||||
} while (i != end);
|
||||
// stay on same guy?
|
||||
i = spec_track[pnum];
|
||||
s = &cl.players[i];
|
||||
if (s->name[0] && !s->spectator)
|
||||
{
|
||||
Cam_Lock(pnum, i);
|
||||
return;
|
||||
}
|
||||
Con_Printf("No target found ...\n");
|
||||
autocam[pnum] = locked[pnum] = false;
|
||||
}
|
||||
|
||||
void Cam_Reset(void)
|
||||
{
|
||||
int pnum;
|
||||
for (pnum = 0; pnum < MAX_SPLITS; pnum++)
|
||||
{
|
||||
autocam[pnum] = CAM_NONE;
|
||||
spec_track[pnum] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CL_InitCam(void)
|
||||
{
|
||||
Cvar_Register (&cl_hightrack, cl_spectatorgroup);
|
||||
Cvar_Register (&cl_chasecam, cl_spectatorgroup);
|
||||
// Cvar_Register (&cl_camera_maxpitch, cl_spectatorgroup);
|
||||
// Cvar_Register (&cl_camera_maxyaw, cl_spectatorgroup);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,100 @@
|
|||
|
||||
#define SS_FTESERVER 1 //hehehe...
|
||||
#define SS_QUAKE2 2 //useful (and cool). Could be blamed for swamping.
|
||||
#define SS_NETQUAKE 4
|
||||
#define SS_FAVORITE 8 //filter all others.
|
||||
#define SS_KEEPINFO 16
|
||||
|
||||
|
||||
//despite not supporting nq or q2, we still load them. We just filter them. This is to make sure we properly write the listing files.
|
||||
#define MT_BAD 0 //this would be an error
|
||||
#define MT_BCASTQW 1 //-1status
|
||||
#define MT_BCASTQ2 2 //-1status
|
||||
#define MT_BCASTNQ 3 //see code
|
||||
#define MT_SINGLEQW 4 //-1status
|
||||
#define MT_SINGLEQ2 5 //-1status
|
||||
#define MT_SINGLENQ 6 //see code.
|
||||
#define MT_MASTERQW 7 //c\n\0
|
||||
#define MT_MASTERQ2 8 //query
|
||||
|
||||
|
||||
//contains info about a server in greater detail. Could be too mem intensive.
|
||||
typedef struct serverdetailedinfo_s {
|
||||
char info[MAX_SERVERINFO_STRING];
|
||||
|
||||
int numplayers;
|
||||
|
||||
struct {
|
||||
int userid;
|
||||
int frags;
|
||||
float time;
|
||||
int ping;
|
||||
char name[64];
|
||||
char skin[64];
|
||||
char topc;
|
||||
char botc;
|
||||
} players[MAX_CLIENTS];
|
||||
} serverdetailedinfo_t;
|
||||
|
||||
//hold minimum info.
|
||||
typedef struct serverinfo_s {
|
||||
char name[64]; //hostname.
|
||||
netadr_t adr;
|
||||
|
||||
short players;
|
||||
short maxplayers;
|
||||
|
||||
short tl;
|
||||
short fl;
|
||||
char gamedir[8+1];
|
||||
char map[8+1];
|
||||
|
||||
float refreshtime;
|
||||
qbyte special; //flags
|
||||
unsigned short ping;
|
||||
int sends;
|
||||
|
||||
serverdetailedinfo_t *moreinfo;
|
||||
|
||||
struct serverinfo_s *next;
|
||||
} serverinfo_t;
|
||||
|
||||
typedef struct master_s{
|
||||
struct master_s *next;
|
||||
netadr_t adr;
|
||||
int type;
|
||||
char name[1];
|
||||
} master_t;
|
||||
|
||||
struct {
|
||||
qboolean inuse;
|
||||
netadr_t adr;
|
||||
|
||||
serverdetailedinfo_t *detail;
|
||||
|
||||
int linenum;
|
||||
} selectedserver;
|
||||
|
||||
typedef struct player_s {
|
||||
char name[16];
|
||||
int frags;
|
||||
int colour;
|
||||
char skin[8];
|
||||
netadr_t adr;
|
||||
|
||||
struct player_s *next;
|
||||
} player_t;
|
||||
|
||||
void SListOptionChanged(serverinfo_t *newserver);
|
||||
|
||||
extern serverinfo_t *firstserver;
|
||||
extern master_t *master;
|
||||
extern player_t *mplayers;
|
||||
|
||||
void CL_QueryServers(void);
|
||||
int NET_CheckPollSockets(void);
|
||||
void MasterInfo_Request(master_t *mast);
|
||||
serverinfo_t *Master_InfoForServer (netadr_t addr);
|
||||
serverinfo_t *Master_InfoForNum (int num);
|
||||
int Master_TotalCount(void);
|
||||
void Master_QueryServer(serverinfo_t *server);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,726 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
|
||||
cvar_t cl_nopred = {"cl_nopred","0"};
|
||||
cvar_t cl_pushlatency = {"pushlatency","-999"};
|
||||
|
||||
extern frame_t *view_frame;
|
||||
|
||||
#define MAX_PARSE_ENTITIES 1024
|
||||
extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
|
||||
int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles);
|
||||
|
||||
|
||||
extern float pm_airaccelerate;
|
||||
|
||||
extern usercmd_t independantphysics[MAX_SPLITS];
|
||||
|
||||
#ifdef Q2CLIENT
|
||||
char *Get_Q2ConfigString(int i);
|
||||
|
||||
#ifdef Q2BSPS
|
||||
void Q2_Pmove (q2pmove_t *pmove);
|
||||
#define Q2PMF_DUCKED 1
|
||||
#define Q2PMF_JUMP_HELD 2
|
||||
#define Q2PMF_ON_GROUND 4
|
||||
#define Q2PMF_TIME_WATERJUMP 8 // pm_time is waterjump
|
||||
#define Q2PMF_TIME_LAND 16 // pm_time is time before rejump
|
||||
#define Q2PMF_TIME_TELEPORT 32 // pm_time is non-moving time
|
||||
#define Q2PMF_NO_PREDICTION 64 // temporarily disables prediction (used for grappling hook)
|
||||
#endif
|
||||
|
||||
vec3_t cl_predicted_origins[UPDATE_BACKUP];
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CL_CheckPredictionError
|
||||
===================
|
||||
*/
|
||||
#ifdef Q2BSPS
|
||||
void CLQ2_CheckPredictionError (void)
|
||||
{
|
||||
int frame;
|
||||
int delta[3];
|
||||
int i;
|
||||
int len;
|
||||
|
||||
if (cl_nopred.value || (cl.q2frame.playerstate.pmove.pm_flags & Q2PMF_NO_PREDICTION))
|
||||
return;
|
||||
|
||||
// calculate the last usercmd_t we sent that the server has processed
|
||||
frame = cls.netchan.incoming_acknowledged;
|
||||
frame &= (UPDATE_MASK);
|
||||
|
||||
// compare what the server returned with what we had predicted it to be
|
||||
VectorSubtract (cl.q2frame.playerstate.pmove.origin, cl_predicted_origins[frame], delta);
|
||||
|
||||
// save the prediction error for interpolation
|
||||
len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
|
||||
if (len > 640) // 80 world units
|
||||
{ // a teleport or something
|
||||
VectorClear (cl.prediction_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (/*cl_showmiss->value && */(delta[0] || delta[1] || delta[2]) )
|
||||
Con_Printf ("prediction miss on %i: %i\n", cl.q2frame.serverframe,
|
||||
delta[0] + delta[1] + delta[2]);
|
||||
|
||||
VectorCopy (cl.q2frame.playerstate.pmove.origin, cl_predicted_origins[frame]);
|
||||
|
||||
// save for error itnerpolation
|
||||
for (i=0 ; i<3 ; i++)
|
||||
cl.prediction_error[i] = delta[i]*0.125;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_ClipMoveToEntities
|
||||
|
||||
====================
|
||||
*/
|
||||
void CLQ2_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
|
||||
{
|
||||
int i, x, zd, zu;
|
||||
trace_t trace;
|
||||
int headnode;
|
||||
float *angles;
|
||||
entity_state_t *ent;
|
||||
int num;
|
||||
model_t *cmodel;
|
||||
vec3_t bmins, bmaxs;
|
||||
|
||||
for (i=0 ; i<cl.q2frame.num_entities ; i++)
|
||||
{
|
||||
num = (cl.q2frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
|
||||
ent = &cl_parse_entities[num];
|
||||
|
||||
if (!ent->solid)
|
||||
continue;
|
||||
|
||||
if (ent->number == cl.playernum[0]+1)
|
||||
continue;
|
||||
|
||||
if (ent->solid == 31)
|
||||
{ // special value for bmodel
|
||||
cmodel = cl.model_precache[ent->modelindex];
|
||||
if (!cmodel)
|
||||
continue;
|
||||
headnode = cmodel->hulls[0].firstclipnode;
|
||||
angles = ent->angles;
|
||||
}
|
||||
else
|
||||
{ // encoded bbox
|
||||
x = 8*(ent->solid & 31);
|
||||
zd = 8*((ent->solid>>5) & 31);
|
||||
zu = 8*((ent->solid>>10) & 63) - 32;
|
||||
|
||||
bmins[0] = bmins[1] = -x;
|
||||
bmaxs[0] = bmaxs[1] = x;
|
||||
bmins[2] = -zd;
|
||||
bmaxs[2] = zu;
|
||||
|
||||
headnode = CM_HeadnodeForBox (bmins, bmaxs);
|
||||
angles = vec3_origin; // boxes don't rotate
|
||||
}
|
||||
|
||||
if (tr->allsolid)
|
||||
return;
|
||||
|
||||
trace = CM_TransformedBoxTrace (start, end,
|
||||
mins, maxs, headnode, MASK_PLAYERSOLID,
|
||||
ent->origin, angles);
|
||||
|
||||
if (trace.allsolid || trace.startsolid ||
|
||||
trace.fraction < tr->fraction)
|
||||
{
|
||||
trace.ent = (struct edict_s *)ent;
|
||||
if (tr->startsolid)
|
||||
{
|
||||
*tr = trace;
|
||||
tr->startsolid = true;
|
||||
}
|
||||
else
|
||||
*tr = trace;
|
||||
}
|
||||
else if (trace.startsolid)
|
||||
tr->startsolid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CL_PMTrace
|
||||
================
|
||||
*/
|
||||
q2trace_t CLQ2_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
|
||||
{
|
||||
q2trace_t q2t;
|
||||
trace_t t;
|
||||
|
||||
// check against world
|
||||
t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
|
||||
if (t.fraction < 1.0)
|
||||
t.ent = (struct edict_s *)1;
|
||||
|
||||
// check all other solid models
|
||||
CLQ2_ClipMoveToEntities (start, mins, maxs, end, &t);
|
||||
|
||||
q2t.allsolid = t.allsolid;
|
||||
q2t.contents = t.contents;
|
||||
VectorCopy(t.endpos, q2t.endpos);
|
||||
q2t.ent = t.ent;
|
||||
q2t.fraction = t.fraction;
|
||||
q2t.plane = t.plane;
|
||||
q2t.startsolid = t.startsolid;
|
||||
q2t.surface = t.surface;
|
||||
|
||||
return q2t;
|
||||
}
|
||||
|
||||
int CLQ2_PMpointcontents (vec3_t point)
|
||||
{
|
||||
int i;
|
||||
entity_state_t *ent;
|
||||
int num;
|
||||
model_t *cmodel;
|
||||
int contents;
|
||||
|
||||
contents = CM_PointContents (point, 0);
|
||||
|
||||
for (i=0 ; i<cl.q2frame.num_entities ; i++)
|
||||
{
|
||||
num = (cl.q2frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
|
||||
ent = &cl_parse_entities[num];
|
||||
|
||||
if (ent->solid != 31) // special value for bmodel
|
||||
continue;
|
||||
|
||||
cmodel = cl.model_precache[ent->modelindex];
|
||||
if (!cmodel)
|
||||
continue;
|
||||
|
||||
contents |= CM_TransformedPointContents (point, cmodel->hulls[0].firstclipnode, ent->origin, ent->angles);
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
=================
|
||||
CL_PredictMovement
|
||||
|
||||
Sets cl.predicted_origin and cl.predicted_angles
|
||||
=================
|
||||
*/
|
||||
void CLQ2_PredictMovement (void) //q2 doesn't support split clients.
|
||||
{
|
||||
#ifdef Q2BSPS
|
||||
int ack, current;
|
||||
int frame;
|
||||
int oldframe;
|
||||
usercmd_t *cmd;
|
||||
q2pmove_t pm;
|
||||
int step;
|
||||
int oldz;
|
||||
#endif
|
||||
int i;
|
||||
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
// if (cl_paused->value)
|
||||
// return;
|
||||
|
||||
#ifdef Q2BSPS
|
||||
if (cl_nopred.value || (cl.q2frame.playerstate.pmove.pm_flags & Q2PMF_NO_PREDICTION))
|
||||
#endif
|
||||
{ // just set angles
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
cl.predicted_angles[i] = cl.viewangles[0][i] + SHORT2ANGLE(cl.q2frame.playerstate.pmove.delta_angles[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#ifdef Q2BSPS
|
||||
ack = cls.netchan.incoming_acknowledged;
|
||||
current = cls.netchan.outgoing_sequence;
|
||||
|
||||
// if we are too far out of date, just freeze
|
||||
if (current - ack >= UPDATE_MASK)
|
||||
{
|
||||
// if (cl_showmiss->value)
|
||||
Con_Printf ("exceeded CMD_BACKUP\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy current state to pmove
|
||||
memset (&pm, 0, sizeof(pm));
|
||||
pm.trace = CLQ2_PMTrace;
|
||||
pm.pointcontents = CLQ2_PMpointcontents;
|
||||
|
||||
pm_airaccelerate = atof(Get_Q2ConfigString(Q2CS_AIRACCEL));
|
||||
|
||||
pm.s = cl.q2frame.playerstate.pmove;
|
||||
|
||||
// SCR_DebugGraph (current - ack - 1, 0);
|
||||
|
||||
frame = 0;
|
||||
|
||||
// run frames
|
||||
while (++ack < current)
|
||||
{
|
||||
frame = ack & (UPDATE_MASK);
|
||||
cmd = &cl.frames[frame].cmd[0];
|
||||
|
||||
pm.cmd = *cmd;
|
||||
Q2_Pmove (&pm);
|
||||
|
||||
// save for debug checking
|
||||
VectorCopy (pm.s.origin, cl_predicted_origins[frame]);
|
||||
}
|
||||
|
||||
if (independantphysics[0].msec)
|
||||
{
|
||||
cmd = &independantphysics[0];
|
||||
|
||||
pm.cmd = *cmd;
|
||||
Q2_Pmove (&pm);
|
||||
}
|
||||
|
||||
oldframe = (ack-2) & (UPDATE_MASK);
|
||||
oldz = cl_predicted_origins[oldframe][2];
|
||||
step = pm.s.origin[2] - oldz;
|
||||
if (step > 63 && step < 160 && (pm.s.pm_flags & Q2PMF_ON_GROUND) )
|
||||
{
|
||||
cl.predicted_step = step * 0.125;
|
||||
cl.predicted_step_time = realtime - host_frametime * 500;
|
||||
}
|
||||
|
||||
cl.onground[0] = !!(pm.s.pm_flags & Q2PMF_ON_GROUND);
|
||||
|
||||
|
||||
// copy results out for rendering
|
||||
cl.predicted_origin[0] = pm.s.origin[0]*0.125;
|
||||
cl.predicted_origin[1] = pm.s.origin[1]*0.125;
|
||||
cl.predicted_origin[2] = pm.s.origin[2]*0.125;
|
||||
|
||||
VectorCopy (pm.viewangles, cl.predicted_angles);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_NudgePosition
|
||||
|
||||
If pmove.origin is in a solid position,
|
||||
try nudging slightly on all axis to
|
||||
allow for the cut precision of the net coordinates
|
||||
=================
|
||||
*/
|
||||
void CL_NudgePosition (void)
|
||||
{
|
||||
vec3_t base;
|
||||
int x, y;
|
||||
|
||||
if (cl.worldmodel->hulls->funcs.HullPointContents (cl.worldmodel->hulls, pmove.origin) == FTECONTENTS_EMPTY)
|
||||
return;
|
||||
|
||||
VectorCopy (pmove.origin, base);
|
||||
for (x=-1 ; x<=1 ; x++)
|
||||
{
|
||||
for (y=-1 ; y<=1 ; y++)
|
||||
{
|
||||
pmove.origin[0] = base[0] + x * 1.0/8;
|
||||
pmove.origin[1] = base[1] + y * 1.0/8;
|
||||
if (cl.worldmodel->hulls->funcs.HullPointContents (cl.worldmodel->hulls, pmove.origin) == FTECONTENTS_EMPTY)
|
||||
return;
|
||||
}
|
||||
}
|
||||
Con_DPrintf ("CL_NudgePosition: stuck\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_PredictUsercmd
|
||||
==============
|
||||
*/
|
||||
void CL_PredictUsercmd (int pnum, player_state_t *from, player_state_t *to, usercmd_t *u)
|
||||
{
|
||||
extern vec3_t player_mins;
|
||||
extern vec3_t player_maxs;
|
||||
// split up very long moves
|
||||
if (u->msec > 50) {
|
||||
player_state_t temp;
|
||||
usercmd_t split;
|
||||
|
||||
split = *u;
|
||||
split.msec /= 2;
|
||||
|
||||
CL_PredictUsercmd (pnum, from, &temp, &split);
|
||||
CL_PredictUsercmd (pnum, &temp, to, &split);
|
||||
return;
|
||||
}
|
||||
|
||||
VectorCopy (from->origin, pmove.origin);
|
||||
VectorCopy (u->angles, pmove.angles);
|
||||
VectorCopy (from->velocity, pmove.velocity);
|
||||
|
||||
pmove.jump_msec = (cls.z_ext & Z_EXT_PM_TYPE) ? 0 : from->jump_msec;
|
||||
pmove.jump_held = from->jump_held;
|
||||
pmove.waterjumptime = from->waterjumptime;
|
||||
pmove.pm_type = from->pm_type;
|
||||
|
||||
pmove.cmd = *u;
|
||||
|
||||
movevars.entgravity = cl.entgravity[pnum];
|
||||
movevars.maxspeed = cl.maxspeed[pnum];
|
||||
movevars.bunnyspeedcap = cl.bunnyspeedcap;
|
||||
pmove.onladder = false;
|
||||
pmove.hullnum = from->hullnum;
|
||||
|
||||
if (cl.worldmodel->fromgame == fg_quake2 || pmove.hullnum > MAX_MAP_HULLSM)
|
||||
{
|
||||
player_mins[0] = -16;
|
||||
player_mins[1] = -16;
|
||||
player_mins[2] = -24;
|
||||
player_maxs[0] = 16;
|
||||
player_maxs[1] = 16;
|
||||
player_maxs[2] = 32;
|
||||
|
||||
VectorScale(player_mins, pmove.hullnum/56.0f, player_mins);
|
||||
VectorScale(player_maxs, pmove.hullnum/56.0f, player_maxs);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy(cl.worldmodel->hulls[pmove.hullnum].clip_mins, player_mins);
|
||||
VectorCopy(cl.worldmodel->hulls[pmove.hullnum].clip_maxs, player_maxs);
|
||||
}
|
||||
if (DEFAULT_VIEWHEIGHT > player_maxs[2])
|
||||
{
|
||||
player_maxs[2] -= player_mins[2];
|
||||
player_mins[2] = 0;
|
||||
}
|
||||
|
||||
PM_PlayerMove ();
|
||||
|
||||
to->waterjumptime = pmove.waterjumptime;
|
||||
to->jump_held = pmove.jump_held;
|
||||
to->jump_msec = pmove.jump_msec;
|
||||
pmove.jump_msec = 0;
|
||||
|
||||
VectorCopy (pmove.origin, to->origin);
|
||||
VectorCopy (pmove.angles, to->viewangles);
|
||||
VectorCopy (pmove.velocity, to->velocity);
|
||||
to->onground = pmove.onground;
|
||||
|
||||
to->weaponframe = from->weaponframe;
|
||||
to->pm_type = from->pm_type;
|
||||
to->hullnum = from->hullnum;
|
||||
}
|
||||
|
||||
|
||||
//Used when cl_nopred is 1 to determine whether we are on ground, otherwise stepup smoothing code produces ugly jump physics
|
||||
void CL_CatagorizePosition (int pnum)
|
||||
{
|
||||
if (cl.spectator)
|
||||
{
|
||||
cl.onground[pnum] = false; // in air
|
||||
return;
|
||||
}
|
||||
VectorClear (pmove.velocity);
|
||||
VectorCopy (cl.simorg[pnum], pmove.origin);
|
||||
pmove.numtouch = 0;
|
||||
PM_CategorizePosition ();
|
||||
cl.onground[pnum] = pmove.onground;
|
||||
}
|
||||
//Smooth out stair step ups.
|
||||
//Called before CL_EmitEntities so that the player's lightning model origin is updated properly
|
||||
void CL_CalcCrouch (int pnum)
|
||||
{
|
||||
qboolean teleported;
|
||||
static vec3_t oldorigin[MAX_SPLITS];
|
||||
static float oldz[MAX_SPLITS] = {0}, extracrouch[MAX_SPLITS] = {0}, crouchspeed[MAX_SPLITS] = {100,100};
|
||||
vec3_t delta;
|
||||
|
||||
VectorSubtract(cl.simorg[pnum], oldorigin[pnum], delta);
|
||||
|
||||
teleported = Length(delta)>48;
|
||||
VectorCopy (cl.simorg[pnum], oldorigin[pnum]);
|
||||
|
||||
if (teleported)
|
||||
{
|
||||
// possibly teleported or respawned
|
||||
oldz[pnum] = cl.simorg[pnum][2];
|
||||
extracrouch[pnum] = 0;
|
||||
crouchspeed[pnum] = 100;
|
||||
cl.crouch[pnum] = 0;
|
||||
VectorCopy (cl.simorg[pnum], oldorigin[pnum]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cl.onground[pnum] && cl.simorg[pnum][2] - oldz[pnum] > 0)
|
||||
{
|
||||
if (cl.simorg[pnum][2] - oldz[pnum] > 20)
|
||||
{
|
||||
// if on steep stairs, increase speed
|
||||
if (crouchspeed[pnum] < 160)
|
||||
{
|
||||
extracrouch[pnum] = cl.simorg[pnum][2] - oldz[pnum] - host_frametime * 200 - 15;
|
||||
extracrouch[pnum] = min(extracrouch[pnum], 5);
|
||||
}
|
||||
crouchspeed[pnum] = 160;
|
||||
}
|
||||
|
||||
oldz[pnum] += host_frametime * crouchspeed[pnum];
|
||||
if (oldz[pnum] > cl.simorg[pnum][2])
|
||||
oldz[pnum] = cl.simorg[pnum][2];
|
||||
|
||||
if (cl.simorg[pnum][2] - oldz[pnum] > 15 + extracrouch[pnum])
|
||||
oldz[pnum] = cl.simorg[pnum][2] - 15 - extracrouch[pnum];
|
||||
extracrouch[pnum] -= host_frametime * 200;
|
||||
extracrouch[pnum] = max(extracrouch[pnum], 0);
|
||||
|
||||
cl.crouch[pnum] = oldz[pnum] - cl.simorg[pnum][2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// in air or moving down
|
||||
oldz[pnum] = cl.simorg[pnum][2];
|
||||
cl.crouch[pnum] += host_frametime * 150;
|
||||
if (cl.crouch[pnum] > 0)
|
||||
cl.crouch[pnum] = 0;
|
||||
crouchspeed[pnum] = 100;
|
||||
extracrouch[pnum] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_PredictMove
|
||||
==============
|
||||
*/
|
||||
void CL_PredictMovePNum (int pnum)
|
||||
{
|
||||
frame_t ind;
|
||||
int i;
|
||||
float f;
|
||||
frame_t *from, *to = NULL;
|
||||
int oldphysent;
|
||||
|
||||
//these are to make svc_viewentity work better
|
||||
float *vel;
|
||||
float *org;
|
||||
#ifdef Q2CLIENT
|
||||
if (cls.q2server)
|
||||
{
|
||||
cl.crouch[pnum] = 0;
|
||||
CLQ2_PredictMovement();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cl_pushlatency.value > 0)
|
||||
Cvar_Set (&cl_pushlatency, "0");
|
||||
|
||||
if (cl.paused)
|
||||
return;
|
||||
#ifdef NQPROT
|
||||
if (cls.demoplayback!=DPB_NETQUAKE) //don't increase time in nq demos.
|
||||
#endif
|
||||
{
|
||||
cl.time = realtime - cls.latency - cl_pushlatency.value*0.001;
|
||||
if (cl.time > realtime)
|
||||
cl.time = realtime;
|
||||
}
|
||||
/* else
|
||||
{
|
||||
entitystate_t
|
||||
cl.crouch = 0;
|
||||
VectorCopy(cl
|
||||
return;
|
||||
}
|
||||
*/
|
||||
if (cl.intermission)
|
||||
{
|
||||
cl.crouch[pnum] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cl.validsequence)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.netchan.outgoing_sequence - cls.netchan.incoming_sequence >= UPDATE_BACKUP-1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.state == ca_onserver)
|
||||
{ // first update is the final signon stage
|
||||
char text[1024];
|
||||
|
||||
cls.state = ca_active;
|
||||
sprintf (text, "FTE QuakeWorld: %s", cls.servername);
|
||||
#ifdef _WIN32
|
||||
SetWindowText (mainwindow, text);
|
||||
#endif
|
||||
SCR_EndLoadingPlaque();
|
||||
}
|
||||
|
||||
|
||||
VectorCopy (cl.viewangles[pnum], cl.simangles[pnum]);
|
||||
|
||||
// this is the last frame received from the server
|
||||
from = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
|
||||
|
||||
vel = from->playerstate[cl.playernum[pnum]].velocity;
|
||||
org = from->playerstate[cl.playernum[pnum]].origin;
|
||||
|
||||
#ifdef PEXT_SETVIEW
|
||||
if (cl.viewentity[pnum])
|
||||
{
|
||||
entity_state_t *CL_FindPacketEntity(int num);
|
||||
entity_state_t *state;
|
||||
state = CL_FindPacketEntity (cl.viewentity[pnum]);
|
||||
if (state)
|
||||
{
|
||||
org = state->origin;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ((cl_nopred.value|| cl.fixangle) || cls.demoplayback==DPB_MVD)
|
||||
{
|
||||
VectorCopy (vel, cl.simvel[pnum]);
|
||||
VectorCopy (org, cl.simorg[pnum]);
|
||||
|
||||
to = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
|
||||
|
||||
|
||||
|
||||
CL_CatagorizePosition(pnum);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// predict forward until cl.time <= to->senttime
|
||||
oldphysent = pmove.numphysent;
|
||||
CL_SetSolidPlayers (cl.playernum[pnum]);
|
||||
|
||||
to = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
|
||||
|
||||
for (i=1 ; i<UPDATE_BACKUP-1 && cls.netchan.incoming_sequence+i <
|
||||
cls.netchan.outgoing_sequence; i++)
|
||||
{
|
||||
to = &cl.frames[(cls.netchan.incoming_sequence+i) & UPDATE_MASK];
|
||||
CL_PredictUsercmd (pnum, &from->playerstate[cl.playernum[pnum]]
|
||||
, &to->playerstate[cl.playernum[pnum]], &to->cmd[pnum]);
|
||||
|
||||
cl.onground[pnum] = pmove.onground;
|
||||
|
||||
if (to->senttime >= cl.time)
|
||||
break;
|
||||
from = to;
|
||||
}
|
||||
|
||||
if (independantphysics[pnum].msec)
|
||||
{
|
||||
from = to;
|
||||
to = &ind;
|
||||
to->cmd[pnum] = independantphysics[pnum];
|
||||
to->senttime = cl.time;
|
||||
CL_PredictUsercmd (pnum, &from->playerstate[cl.playernum[pnum]]
|
||||
, &to->playerstate[cl.playernum[pnum]], &to->cmd[pnum]);
|
||||
|
||||
cl.onground[pnum] = pmove.onground;
|
||||
}
|
||||
|
||||
pmove.numphysent = oldphysent;
|
||||
|
||||
if (1)//!independantphysics.msec)
|
||||
{
|
||||
VectorCopy (to->playerstate[cl.playernum[pnum]].velocity, cl.simvel[pnum]);
|
||||
VectorCopy (to->playerstate[cl.playernum[pnum]].origin, cl.simorg[pnum]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// now interpolate some fraction of the final frame
|
||||
if (to->senttime == from->senttime)
|
||||
f = 0;
|
||||
else
|
||||
{
|
||||
f = (cl.time - from->senttime) / (to->senttime - from->senttime);
|
||||
|
||||
if (f < 0)
|
||||
f = 0;
|
||||
if (f > 1)
|
||||
f = 1;
|
||||
}
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if ( fabs(org[i] - to->playerstate[cl.playernum[pnum]].origin[i]) > 128)
|
||||
{ // teleported, so don't lerp
|
||||
VectorCopy (to->playerstate[cl.playernum[pnum]].velocity, cl.simvel[pnum]);
|
||||
VectorCopy (to->playerstate[cl.playernum[pnum]].origin, cl.simorg[pnum]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
cl.simorg[pnum][i] = org[i]
|
||||
+ f*(to->playerstate[cl.playernum[pnum]].origin[i] - org[i]);
|
||||
cl.simvel[pnum][i] = vel[i]
|
||||
+ f*(to->playerstate[cl.playernum[pnum]].velocity[i] - vel[i]);
|
||||
}
|
||||
CL_CatagorizePosition(pnum);
|
||||
|
||||
}
|
||||
out:
|
||||
CL_CalcCrouch (pnum);
|
||||
}
|
||||
|
||||
void CL_PredictMove (void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cl.splitclients; i++)
|
||||
CL_PredictMovePNum(i);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_InitPrediction
|
||||
==============
|
||||
*/
|
||||
void CL_InitPrediction (void)
|
||||
{
|
||||
extern char cl_predictiongroup[];
|
||||
Cvar_Register (&cl_pushlatency, cl_predictiongroup);
|
||||
Cvar_Register (&cl_nopred, cl_predictiongroup);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,813 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// client.h
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[16];
|
||||
int width;
|
||||
int height;
|
||||
int cachedbpp;
|
||||
qboolean failedload; // the name isn't a valid skin
|
||||
cache_user_t cache;
|
||||
} skin_t;
|
||||
|
||||
// player_state_t is the information needed by a player entity
|
||||
// to do move prediction and to generate a drawable entity
|
||||
typedef struct
|
||||
{
|
||||
int messagenum; // all player's won't be updated each frame
|
||||
|
||||
double state_time; // not the same as the packet time,
|
||||
// because player commands come asyncronously
|
||||
usercmd_t command; // last command for prediction
|
||||
|
||||
vec3_t origin;
|
||||
vec3_t viewangles; // only for demos, not from server
|
||||
vec3_t velocity;
|
||||
int weaponframe;
|
||||
|
||||
int modelindex;
|
||||
int frame;
|
||||
int skinnum;
|
||||
int effects;
|
||||
|
||||
#ifdef PEXT_SCALE
|
||||
float scale;
|
||||
#endif
|
||||
#ifdef PEXT_TRANS
|
||||
float trans;
|
||||
#endif
|
||||
#ifdef PEXT_FATNESS
|
||||
float fatness;
|
||||
#endif
|
||||
|
||||
int flags; // dead, gib, etc
|
||||
|
||||
int pm_type;
|
||||
float waterjumptime;
|
||||
qboolean onground;
|
||||
qboolean jump_held;
|
||||
int jump_msec; // hack for fixing bunny-hop flickering on non-ZQuake servers
|
||||
int hullnum;
|
||||
|
||||
float lerpstarttime;
|
||||
int oldframe;
|
||||
} player_state_t;
|
||||
|
||||
|
||||
#if defined(Q2CLIENT) || defined(Q2SERVER)
|
||||
typedef enum
|
||||
{
|
||||
// can accelerate and turn
|
||||
Q2PM_NORMAL,
|
||||
Q2PM_SPECTATOR,
|
||||
// no acceleration or turning
|
||||
Q2PM_DEAD,
|
||||
Q2PM_GIB, // different bounding box
|
||||
Q2PM_FREEZE
|
||||
} q2pmtype_t;
|
||||
typedef struct
|
||||
{ //shared with q2 dll
|
||||
|
||||
q2pmtype_t pm_type;
|
||||
|
||||
short origin[3]; // 12.3
|
||||
short velocity[3]; // 12.3
|
||||
qbyte pm_flags; // ducked, jump_held, etc
|
||||
qbyte pm_time; // each unit = 8 ms
|
||||
short gravity;
|
||||
short delta_angles[3]; // add to command angles to get view direction
|
||||
// changed by spawns, rotating objects, and teleporters
|
||||
} q2pmove_state_t;
|
||||
|
||||
typedef struct
|
||||
{ //shared with q2 dll
|
||||
|
||||
q2pmove_state_t pmove; // for prediction
|
||||
|
||||
// these fields do not need to be communicated bit-precise
|
||||
|
||||
vec3_t viewangles; // for fixed views
|
||||
vec3_t viewoffset; // add to pmovestate->origin
|
||||
vec3_t kick_angles; // add to view direction to get render angles
|
||||
// set by weapon kicks, pain effects, etc
|
||||
|
||||
vec3_t gunangles;
|
||||
vec3_t gunoffset;
|
||||
int gunindex;
|
||||
int gunframe;
|
||||
|
||||
float blend[4]; // rgba full screen effect
|
||||
|
||||
float fov; // horizontal field of view
|
||||
|
||||
int rdflags; // refdef flags
|
||||
|
||||
short stats[Q2MAX_STATS]; // fast status bar updates
|
||||
} q2player_state_t;
|
||||
#endif
|
||||
|
||||
#define MAX_SCOREBOARDNAME 16
|
||||
typedef struct player_info_s
|
||||
{
|
||||
int userid;
|
||||
char userinfo[MAX_INFO_STRING];
|
||||
|
||||
// scoreboard information
|
||||
char name[MAX_SCOREBOARDNAME];
|
||||
char team[MAX_INFO_KEY];
|
||||
float entertime;
|
||||
int frags;
|
||||
int ping;
|
||||
qbyte pl;
|
||||
|
||||
// skin information
|
||||
int topcolor;
|
||||
int bottomcolor;
|
||||
|
||||
int _topcolor;
|
||||
int _bottomcolor;
|
||||
|
||||
int spectator;
|
||||
qbyte translations[VID_GRADES*256];
|
||||
skin_t *skin;
|
||||
|
||||
struct model_s *model;
|
||||
|
||||
unsigned short vweapindex;
|
||||
|
||||
int prevcount;
|
||||
} player_info_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// generated on client side
|
||||
usercmd_t cmd[MAX_SPLITS]; // cmd that generated the frame
|
||||
double senttime; // time cmd was sent off
|
||||
int delta_sequence; // sequence number to delta from, -1 = full update
|
||||
|
||||
// received from server
|
||||
double receivedtime; // time message was received, or -1
|
||||
player_state_t playerstate[MAX_CLIENTS]; // message received that reflects performing
|
||||
// the usercmd
|
||||
packet_entities_t packet_entities;
|
||||
qboolean invalid; // true if the packet_entities delta was invalid
|
||||
} frame_t;
|
||||
|
||||
#ifdef Q2CLIENT
|
||||
typedef struct
|
||||
{
|
||||
qboolean valid; // cleared if delta parsing was invalid
|
||||
int serverframe;
|
||||
int servertime; // server time the message is valid for (in msec)
|
||||
int deltaframe;
|
||||
qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits
|
||||
q2player_state_t playerstate;
|
||||
int num_entities;
|
||||
int parse_entities; // non-masked index into cl_parse_entities array
|
||||
} q2frame_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int destcolor[3];
|
||||
int percent; // 0-256
|
||||
} cshift_t;
|
||||
|
||||
#define CSHIFT_CONTENTS 0
|
||||
#define CSHIFT_DAMAGE 1
|
||||
#define CSHIFT_BONUS 2
|
||||
#define CSHIFT_POWERUP 3
|
||||
#define CSHIFT_SERVER 4
|
||||
#define NUM_CSHIFTS 5
|
||||
|
||||
|
||||
//
|
||||
// client_state_t should hold all pieces of the client state
|
||||
//
|
||||
#define MAX_DLIGHTS 32
|
||||
typedef struct dlight_s
|
||||
{
|
||||
int key; // so entities can reuse same entry
|
||||
qboolean noppl;
|
||||
vec3_t origin;
|
||||
float radius;
|
||||
float die; // stop lighting after this time
|
||||
float decay; // drop this each second
|
||||
float minlight; // don't add when contributing less
|
||||
float color[3];
|
||||
float channelfade[3];
|
||||
} dlight_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int length;
|
||||
char map[MAX_STYLESTRING];
|
||||
int colour;
|
||||
} lightstyle_t;
|
||||
|
||||
|
||||
|
||||
#define MAX_EFRAGS 512
|
||||
|
||||
#define MAX_DEMOS 8
|
||||
#define MAX_DEMONAME 16
|
||||
|
||||
typedef enum {
|
||||
ca_disconnected, // full screen console with no connection
|
||||
ca_demostart, // starting up a demo
|
||||
ca_connected, // netchan_t established, waiting for svc_serverdata
|
||||
ca_onserver, // processing data lists, donwloading, etc
|
||||
ca_active // everything is in, so frames can be rendered
|
||||
} cactive_t;
|
||||
|
||||
typedef enum {
|
||||
dl_none,
|
||||
dl_model,
|
||||
dl_sound,
|
||||
dl_skin,
|
||||
dl_wad,
|
||||
dl_single,
|
||||
dl_singlestuffed
|
||||
} dltype_t; // download type
|
||||
|
||||
//
|
||||
// the client_static_t structure is persistant through an arbitrary number
|
||||
// of server connections
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
// connection information
|
||||
cactive_t state;
|
||||
#ifdef Q2CLIENT
|
||||
qboolean q2server;
|
||||
#endif
|
||||
|
||||
qboolean resendinfo;
|
||||
|
||||
// network stuff
|
||||
netchan_t netchan;
|
||||
|
||||
// private userinfo for sending to masterless servers
|
||||
char userinfo[MAX_INFO_STRING];
|
||||
|
||||
char servername[MAX_OSPATH]; // name of server from original connect
|
||||
|
||||
int qport;
|
||||
int socketip;
|
||||
int socketip6;
|
||||
int socketipx;
|
||||
|
||||
enum {DL_NONE, DL_QW, DL_HTTP, DL_FTP} downloadmethod;
|
||||
FILE *downloadqw; // file transfer from server
|
||||
char downloadtempname[MAX_OSPATH];
|
||||
char downloadname[MAX_OSPATH];
|
||||
int downloadnumber;
|
||||
dltype_t downloadtype;
|
||||
int downloadpercent;
|
||||
|
||||
// demo loop control
|
||||
int demonum; // -1 = don't play demos
|
||||
char demos[MAX_DEMOS][MAX_DEMONAME]; // when not playing
|
||||
|
||||
// demo recording info must be here, because record is started before
|
||||
// entering a map (and clearing client_state_t)
|
||||
qboolean demorecording;
|
||||
enum{DPB_NONE,DPB_QUAKEWORLD,DPB_MVD,
|
||||
#ifdef NQPROT
|
||||
DPB_NETQUAKE,
|
||||
#endif
|
||||
#ifdef Q2CLIENT
|
||||
DPB_QUAKE2
|
||||
#endif
|
||||
} demoplayback;
|
||||
qboolean timedemo;
|
||||
FILE *demofile;
|
||||
float td_lastframe; // to meter out one message a frame
|
||||
int td_startframe; // host_framecount at start
|
||||
float td_starttime; // realtime at second frame of timedemo
|
||||
|
||||
int challenge;
|
||||
|
||||
float latency; // rolling average
|
||||
|
||||
qboolean allow_anyparticles;
|
||||
qboolean allow_lightmapgamma;
|
||||
qboolean allow_rearview;
|
||||
qboolean allow_skyboxes;
|
||||
qboolean allow_mirrors;
|
||||
qboolean allow_watervis;
|
||||
qboolean allow_shaders;
|
||||
qboolean allow_luma;
|
||||
qboolean allow_bump;
|
||||
qboolean allow_fbskins;
|
||||
#ifdef FISH
|
||||
qboolean allow_fish;
|
||||
#endif
|
||||
qboolean allow_cheats;
|
||||
qboolean allow_semicheats; //defaults to true, but this allows a server to enforce a strict ruleset (smackdown type rules).
|
||||
float maxfps; //server capped
|
||||
enum {GAME_DEATHMATCH, GAME_COOP} gamemode;
|
||||
|
||||
#ifdef PROTOCOLEXTENSIONS
|
||||
unsigned long fteprotocolextensions;
|
||||
#endif
|
||||
unsigned long z_ext;
|
||||
#ifdef NQPROT
|
||||
struct qsocket_s *netcon;
|
||||
int signon;
|
||||
#endif
|
||||
translation_t language;
|
||||
} client_static_t;
|
||||
|
||||
extern client_static_t cls;
|
||||
|
||||
typedef struct downloadlist_s {
|
||||
char name[128];
|
||||
struct downloadlist_s *next;
|
||||
} downloadlist_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
float lerptime;
|
||||
#ifdef HALFLIFEMODELS
|
||||
float framechange; //marks time of last frame change - for halflife model sequencing.
|
||||
#endif
|
||||
float lerprate; //inverse rate...
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
int frame;
|
||||
float traildist; //when to next throw out a trail
|
||||
} lerpents_t;
|
||||
//
|
||||
// the client_state_t structure is wiped completely at every
|
||||
// server signon
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
int servercount; // server identification for prespawns
|
||||
|
||||
char serverinfo[MAX_SERVERINFO_STRING];
|
||||
|
||||
int parsecount; // server message counter
|
||||
int oldvalidsequence;
|
||||
int validsequence; // this is the sequence number of the last good
|
||||
// packetentity_t we got. If this is 0, we can't
|
||||
// render a frame yet
|
||||
int movemessages; // since connecting to this server
|
||||
// throw out the first couple, so the player
|
||||
// doesn't accidentally do something the
|
||||
// first frame
|
||||
|
||||
int spectator;
|
||||
|
||||
double last_ping_request; // while showing scoreboard
|
||||
double last_servermessage;
|
||||
|
||||
#ifdef Q2CLIENT
|
||||
q2frame_t q2frame;
|
||||
q2frame_t q2frames[Q2UPDATE_BACKUP];
|
||||
#endif
|
||||
|
||||
// sentcmds[cl.netchan.outgoing_sequence & UPDATE_MASK] = cmd
|
||||
frame_t frames[UPDATE_BACKUP];
|
||||
lerpents_t lerpents[MAX_EDICTS];
|
||||
|
||||
// information for local display
|
||||
int stats[MAX_SPLITS][MAX_CL_STATS]; // health, etc
|
||||
float item_gettime[MAX_SPLITS][32]; // cl.time of aquiring item, for blinking
|
||||
float faceanimtime[MAX_SPLITS]; // use anim frame if cl.time < this
|
||||
|
||||
cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups
|
||||
cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types
|
||||
|
||||
// the client maintains its own idea of view angles, which are
|
||||
// sent to the server each frame. And only reset at level change
|
||||
// and teleport times
|
||||
vec3_t viewangles[MAX_SPLITS];
|
||||
|
||||
// the client simulates or interpolates movement to get these values
|
||||
double time; // this is the time value that the client
|
||||
// is rendering at. allways <= realtime
|
||||
float gametime;
|
||||
float gametimemark;
|
||||
|
||||
vec3_t simorg[MAX_SPLITS];
|
||||
vec3_t simvel[MAX_SPLITS];
|
||||
vec3_t simangles[MAX_SPLITS];
|
||||
float rollangle[MAX_SPLITS];
|
||||
|
||||
float minpitch;
|
||||
float maxpitch;
|
||||
|
||||
// pitch drifting vars
|
||||
float pitchvel[MAX_SPLITS];
|
||||
qboolean nodrift[MAX_SPLITS];
|
||||
float driftmove[MAX_SPLITS];
|
||||
double laststop[MAX_SPLITS];
|
||||
|
||||
|
||||
float crouch[MAX_SPLITS]; // local amount for smoothing stepups
|
||||
qboolean onground[MAX_SPLITS];
|
||||
float viewheight[MAX_SPLITS];
|
||||
|
||||
qboolean paused; // send over by server
|
||||
|
||||
float punchangle[MAX_SPLITS]; // temporar yview kick from weapon firing
|
||||
|
||||
int intermission; // don't change view angle, full screen, etc
|
||||
int completed_time; // latched ffrom time at intermission start
|
||||
|
||||
//
|
||||
// information that is static for the entire time connected to a server
|
||||
//
|
||||
char model_name[MAX_MODELS][MAX_QPATH];
|
||||
char sound_name[MAX_SOUNDS][MAX_QPATH];
|
||||
char image_name[Q2MAX_IMAGES][MAX_QPATH];
|
||||
|
||||
struct model_s *model_precache[MAX_MODELS];
|
||||
struct sfx_s *sound_precache[MAX_SOUNDS];
|
||||
|
||||
char skyname[MAX_QPATH];
|
||||
char levelname[40]; // for display on solo scoreboard
|
||||
int playernum[MAX_SPLITS];
|
||||
int splitclients; //we are running this many clients split screen.
|
||||
|
||||
// refresh related state
|
||||
struct model_s *worldmodel; // cl_entitites[0].model
|
||||
struct efrag_s *free_efrags;
|
||||
int num_entities; // stored bottom up in cl_entities array
|
||||
int num_statics; // stored top down in cl_entitiers
|
||||
|
||||
int cdtrack; // cd audio
|
||||
|
||||
entity_t viewent[MAX_SPLITS]; // weapon model
|
||||
|
||||
// all player information
|
||||
player_info_t players[MAX_CLIENTS];
|
||||
|
||||
#ifdef CLPROGS
|
||||
struct edict_s *edicts;
|
||||
int num_edicts;
|
||||
#endif
|
||||
|
||||
downloadlist_t *downloadlist;
|
||||
downloadlist_t *faileddownloads;
|
||||
|
||||
#ifdef PEXT_SETVIEW
|
||||
int viewentity[MAX_SPLITS];
|
||||
#endif
|
||||
qboolean gamedirchanged;
|
||||
|
||||
|
||||
char q2statusbar[1024];
|
||||
char q2layout[1024];
|
||||
int parse_entities;
|
||||
int surpressCount;
|
||||
float lerpfrac;
|
||||
vec3_t predicted_origin;
|
||||
vec3_t predicted_angles;
|
||||
vec3_t prediction_error;
|
||||
float predicted_step_time;
|
||||
float predicted_step;
|
||||
|
||||
// localized movement vars
|
||||
float entgravity[MAX_SPLITS];
|
||||
float maxspeed[MAX_SPLITS];
|
||||
float bunnyspeedcap;
|
||||
qboolean fixangle; //received a fixangle - so disable prediction till the next packet.
|
||||
|
||||
int teamplay;
|
||||
int deathmatch;
|
||||
} client_state_t;
|
||||
|
||||
|
||||
//
|
||||
// cvars
|
||||
//
|
||||
extern cvar_t cl_warncmd;
|
||||
extern cvar_t cl_upspeed;
|
||||
extern cvar_t cl_forwardspeed;
|
||||
extern cvar_t cl_backspeed;
|
||||
extern cvar_t cl_sidespeed;
|
||||
|
||||
extern cvar_t cl_movespeedkey;
|
||||
|
||||
extern cvar_t cl_yawspeed;
|
||||
extern cvar_t cl_pitchspeed;
|
||||
|
||||
extern cvar_t cl_anglespeedkey;
|
||||
|
||||
extern cvar_t cl_shownet;
|
||||
extern cvar_t cl_sbar;
|
||||
extern cvar_t cl_hudswap;
|
||||
|
||||
extern cvar_t cl_pitchdriftspeed;
|
||||
extern cvar_t lookspring;
|
||||
extern cvar_t lookstrafe;
|
||||
extern cvar_t sensitivity;
|
||||
|
||||
extern cvar_t m_pitch;
|
||||
extern cvar_t m_yaw;
|
||||
extern cvar_t m_forward;
|
||||
extern cvar_t m_side;
|
||||
|
||||
extern cvar_t _windowed_mouse;
|
||||
|
||||
extern cvar_t name;
|
||||
|
||||
|
||||
#define MAX_STATIC_ENTITIES 256 // torches, etc
|
||||
|
||||
extern client_state_t cl;
|
||||
|
||||
// FIXME, allocate dynamically
|
||||
extern entity_state_t cl_baselines[MAX_EDICTS];
|
||||
extern efrag_t cl_efrags[MAX_EFRAGS];
|
||||
extern entity_t cl_static_entities[MAX_STATIC_ENTITIES];
|
||||
extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
|
||||
extern dlight_t cl_dlights[MAX_DLIGHTS];
|
||||
|
||||
extern qboolean nomaster;
|
||||
extern float server_version; // version of server we connected to
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
//
|
||||
// cl_main
|
||||
//
|
||||
dlight_t *CL_AllocDlight (int key);
|
||||
void CL_DecayLights (void);
|
||||
void CL_ParseDelta (struct entity_state_s *from, struct entity_state_s *to, int bits, qboolean);
|
||||
|
||||
void CL_Init (void);
|
||||
void Host_WriteConfiguration (void);
|
||||
void CL_CheckServerInfo(void);
|
||||
|
||||
void CL_EstablishConnection (char *host);
|
||||
|
||||
void CL_Disconnect (void);
|
||||
void CL_Disconnect_f (void);
|
||||
void CL_NextDemo (void);
|
||||
qboolean CL_DemoBehind(void);
|
||||
|
||||
void CL_BeginServerConnect(void);
|
||||
void CLNQ_BeginServerConnect(void);
|
||||
|
||||
#define MAX_VISEDICTS 256
|
||||
extern int cl_numvisedicts, cl_oldnumvisedicts;
|
||||
extern entity_t *cl_visedicts, *cl_oldvisedicts;
|
||||
extern entity_t cl_visedicts_list[2][MAX_VISEDICTS];
|
||||
|
||||
extern char emodel_name[], pmodel_name[], prespawn_name[], modellist_name[], soundlist_name[];
|
||||
|
||||
//
|
||||
// cl_input
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
int down[MAX_SPLITS][2]; // key nums holding it down
|
||||
int state[MAX_SPLITS]; // low bit is down state
|
||||
} kbutton_t;
|
||||
|
||||
extern kbutton_t in_mlook, in_klook;
|
||||
extern kbutton_t in_strafe;
|
||||
extern kbutton_t in_speed;
|
||||
|
||||
void CL_InitInput (void);
|
||||
void CL_SendCmd (void);
|
||||
void CL_SendMove (usercmd_t *cmd);
|
||||
#ifdef NQPROT
|
||||
void CL_ParseTEnt (qboolean nqprot);
|
||||
#else
|
||||
void CL_ParseTEnt (void);
|
||||
#endif
|
||||
void CL_UpdateTEnts (void);
|
||||
|
||||
void CL_ClearState (void);
|
||||
|
||||
void CL_ReadPackets (void);
|
||||
void CL_ClampPitch (int pnum);
|
||||
|
||||
int CL_ReadFromServer (void);
|
||||
void CL_WriteToServer (usercmd_t *cmd);
|
||||
void CL_BaseMove (usercmd_t *cmd, int pnum);
|
||||
|
||||
|
||||
float CL_KeyState (kbutton_t *key, int pnum);
|
||||
char *Key_KeynumToString (int keynum);
|
||||
|
||||
//
|
||||
// cl_demo.c
|
||||
//
|
||||
void CL_StopPlayback (void);
|
||||
qboolean CL_GetMessage (void);
|
||||
void CL_WriteDemoCmd (usercmd_t *pcmd);
|
||||
|
||||
void CL_Stop_f (void);
|
||||
void CL_Record_f (void);
|
||||
void CL_ReRecord_f (void);
|
||||
void CL_PlayDemo_f (void);
|
||||
void CL_TimeDemo_f (void);
|
||||
|
||||
//
|
||||
// cl_parse.c
|
||||
//
|
||||
#define NET_TIMINGS 256
|
||||
#define NET_TIMINGSMASK 255
|
||||
extern int packet_latency[NET_TIMINGS];
|
||||
int CL_CalcNet (void);
|
||||
void CL_ParseServerMessage (void);
|
||||
void CLNQ_ParseServerMessage (void);
|
||||
#ifdef Q2CLIENT
|
||||
void CLQ2_ParseServerMessage (void);
|
||||
#endif
|
||||
void CL_NewTranslation (int slot);
|
||||
qboolean CL_CheckOrDownloadFile (char *filename, int nodelay);
|
||||
qboolean CL_IsUploading(void);
|
||||
void CL_NextUpload(void);
|
||||
void CL_StartUpload (qbyte *data, int size);
|
||||
void CL_StopUpload(void);
|
||||
|
||||
void CL_RequestNextDownload (void);
|
||||
|
||||
//
|
||||
// view.c
|
||||
//
|
||||
void V_StartPitchDrift (int pnum);
|
||||
void V_StopPitchDrift (int pnum);
|
||||
|
||||
void V_RenderView (void);
|
||||
void V_UpdatePalette (void);
|
||||
void V_Register (void);
|
||||
void V_ParseDamage (int pnum);
|
||||
void V_SetContentsColor (int contents);
|
||||
void GLV_CalcBlend (void);
|
||||
|
||||
|
||||
//
|
||||
// cl_tent
|
||||
//
|
||||
void CL_InitTEnts (void);
|
||||
void CL_ClearTEnts (void);
|
||||
void CL_ClearCustomTEnts(void);
|
||||
void CL_ParseCustomTEnt(void);
|
||||
|
||||
//
|
||||
// cl_ents.c
|
||||
//
|
||||
void CL_SetSolidPlayers (int playernum);
|
||||
void CL_SetUpPlayerPrediction(qboolean dopred);
|
||||
void CL_EmitEntities (void);
|
||||
void CL_ClearProjectiles (void);
|
||||
void CL_ParseProjectiles (int modelindex);
|
||||
void CL_ParsePacketEntities (qboolean delta);
|
||||
void CL_SetSolidEntities (void);
|
||||
void CL_ParsePlayerinfo (void);
|
||||
void CL_ParseClientPersist(void);
|
||||
|
||||
//
|
||||
// cl_pred.c
|
||||
//
|
||||
void CL_InitPrediction (void);
|
||||
void CL_PredictMove (void);
|
||||
void CL_PredictUsercmd (int pnum, player_state_t *from, player_state_t *to, usercmd_t *u);
|
||||
#ifdef Q2CLIENT
|
||||
void CLQ2_CheckPredictionError (void);
|
||||
#endif
|
||||
|
||||
//
|
||||
// cl_cam.c
|
||||
//
|
||||
#define CAM_NONE 0
|
||||
#define CAM_TRACK 1
|
||||
|
||||
extern int autocam[MAX_SPLITS];
|
||||
extern int spec_track[MAX_SPLITS]; // player# of who we are tracking
|
||||
|
||||
qboolean Cam_DrawViewModel(int pnum);
|
||||
qboolean Cam_DrawPlayer(int pnum, int playernum);
|
||||
void Cam_Track(int pnum, usercmd_t *cmd);
|
||||
void Cam_FinishMove(int pnum, usercmd_t *cmd);
|
||||
void Cam_Reset(void);
|
||||
void CL_InitCam(void);
|
||||
|
||||
//
|
||||
// skin.c
|
||||
//
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char manufacturer;
|
||||
char version;
|
||||
char encoding;
|
||||
char bits_per_pixel;
|
||||
unsigned short xmin,ymin,xmax,ymax;
|
||||
unsigned short hres,vres;
|
||||
unsigned char palette[48];
|
||||
char reserved;
|
||||
char color_planes;
|
||||
unsigned short bytes_per_line;
|
||||
unsigned short palette_type;
|
||||
char filler[58];
|
||||
// unsigned char data; // unbounded
|
||||
} pcx_t;
|
||||
|
||||
|
||||
void Skin_Find (player_info_t *sc);
|
||||
qbyte *Skin_Cache8 (skin_t *skin);
|
||||
qbyte *Skin_Cache32 (skin_t *skin);
|
||||
void Skin_Skins_f (void);
|
||||
void Skin_FlushSkin(char *name);
|
||||
void Skin_AllSkins_f (void);
|
||||
void Skin_NextDownload (void);
|
||||
|
||||
#define RSSHOT_WIDTH 320
|
||||
#define RSSHOT_HEIGHT 200
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//valid.c
|
||||
void Validation_FlushFileList(void);
|
||||
void ValidationPrintVersion(char *f_query_string);
|
||||
void Validation_Server(void);
|
||||
void Validation_FilesModified (void);
|
||||
void Validation_Skins(void);
|
||||
void Validation_CheckIfResponse(char *text);
|
||||
void InitValidation(void);
|
||||
|
||||
extern qboolean f_modified_particles;
|
||||
extern qboolean care_f_modified;
|
||||
|
||||
#ifdef Q2CLIENT
|
||||
void CLQ2_ParseTEnt (void);
|
||||
void CLQ2_AddEntities (void);
|
||||
void CLQ2_ParseBaseline (void);
|
||||
void CLQ2_ParseFrame (void);
|
||||
void CLNQ_ParseEntity(int bits);
|
||||
int CLQ2_RegisterTEntModels (void);
|
||||
#endif
|
||||
|
||||
void NQ_R_ParseParticleEffect (void);
|
||||
void CLNQ_SignonReply (void);
|
||||
void NQ_BeginConnect(char *to);
|
||||
void NQ_ContinueConnect(char *to);
|
||||
int CLNQ_GetMessage (void);
|
||||
|
||||
void CL_BeginServerReconnect(void);
|
||||
|
||||
void SV_User_f (void); //called by client version of the function
|
||||
void SV_Serverinfo_f (void);
|
||||
|
||||
|
||||
|
||||
#ifdef TEXTEDITOR
|
||||
extern qboolean editoractive;
|
||||
extern qboolean editormodal;
|
||||
void Editor_Draw(void);
|
||||
void Editor_Init(void);
|
||||
#endif
|
||||
|
||||
qboolean TP_SoundTrigger(char *message);
|
||||
void CL_AddVWeapModel(entity_t *player, int model);
|
||||
|
||||
|
||||
typedef enum {
|
||||
MFT_NONE,
|
||||
MFT_STATIC, //non-moving, PCX, no sound
|
||||
MFT_ROQ,
|
||||
MFT_AVI,
|
||||
MFT_CIN
|
||||
} media_filmtype_t;
|
||||
extern media_filmtype_t media_filmtype;
|
||||
void Media_Init(void);
|
||||
qboolean Media_PlayFilm(char *name);
|
||||
void CIN_FinishCinematic (void);
|
||||
qboolean CIN_PlayCinematic (char *arg);
|
||||
qboolean CIN_DrawCinematic (void);
|
||||
qboolean CIN_RunCinematic (void);
|
||||
|
||||
void MVD_Interpolate(void);
|
|
@ -0,0 +1,536 @@
|
|||
#include "bothdefs.h"
|
||||
#ifndef NOMEDIA
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qbyte *data;
|
||||
int count;
|
||||
} cblock_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean restart_sound;
|
||||
int s_rate;
|
||||
int s_width;
|
||||
int s_channels;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
qbyte *pic;
|
||||
qbyte *pic_pending;
|
||||
|
||||
// order 1 huffman stuff
|
||||
int *hnodes1; // [256][256][2];
|
||||
int numhnodes1[256];
|
||||
|
||||
int h_used[512];
|
||||
int h_count[512];
|
||||
|
||||
|
||||
int cinematictime;
|
||||
qboolean cinematicpalette_active;
|
||||
qbyte cinematicpalette[768];
|
||||
|
||||
FILE *cinematic_file;
|
||||
int cinematicframe;
|
||||
} cinematics_t;
|
||||
|
||||
cinematics_t cin;
|
||||
|
||||
|
||||
|
||||
|
||||
void CIN_StopCinematic (void)
|
||||
{
|
||||
Media_PlayFilm("");
|
||||
cin.cinematictime = 0; // done
|
||||
if (cin.pic)
|
||||
{
|
||||
Z_Free (cin.pic);
|
||||
cin.pic = NULL;
|
||||
}
|
||||
if (cin.pic_pending)
|
||||
{
|
||||
Z_Free (cin.pic_pending);
|
||||
cin.pic_pending = NULL;
|
||||
}
|
||||
if (cin.cinematicpalette_active)
|
||||
{
|
||||
// re.CinematicSetPalette(NULL);
|
||||
cin.cinematicpalette_active = false;
|
||||
}
|
||||
if (cin.cinematic_file)
|
||||
{
|
||||
fclose (cin.cinematic_file);
|
||||
cin.cinematic_file = NULL;
|
||||
}
|
||||
if (cin.hnodes1)
|
||||
{
|
||||
Z_Free (cin.hnodes1);
|
||||
cin.hnodes1 = NULL;
|
||||
}
|
||||
|
||||
// switch back down to 11 khz sound if necessary
|
||||
if (cin.restart_sound)
|
||||
{
|
||||
cin.restart_sound = false;
|
||||
S_Restart_f ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
SCR_FinishCinematic
|
||||
|
||||
Called when either the cinematic completes, or it is aborted
|
||||
====================
|
||||
*/
|
||||
void CIN_FinishCinematic (void)
|
||||
{
|
||||
// tell the server to advance to the next map / cinematic
|
||||
if (cls.state == ca_active)
|
||||
{
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
SmallestNode1
|
||||
==================
|
||||
*/
|
||||
static int SmallestNode1 (int numhnodes)
|
||||
{
|
||||
int i;
|
||||
int best, bestnode;
|
||||
|
||||
best = 99999999;
|
||||
bestnode = -1;
|
||||
for (i=0 ; i<numhnodes ; i++)
|
||||
{
|
||||
if (cin.h_used[i])
|
||||
continue;
|
||||
if (!cin.h_count[i])
|
||||
continue;
|
||||
if (cin.h_count[i] < best)
|
||||
{
|
||||
best = cin.h_count[i];
|
||||
bestnode = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestnode == -1)
|
||||
return -1;
|
||||
|
||||
cin.h_used[bestnode] = true;
|
||||
return bestnode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Huff1TableInit
|
||||
|
||||
Reads the 64k counts table and initializes the node trees
|
||||
==================
|
||||
*/
|
||||
static void Huff1TableInit (void)
|
||||
{
|
||||
int prev;
|
||||
int j;
|
||||
int *node, *nodebase;
|
||||
qbyte counts[256];
|
||||
int numhnodes;
|
||||
|
||||
cin.hnodes1 = Z_Malloc (256*256*2*4);
|
||||
memset (cin.hnodes1, 0, 256*256*2*4);
|
||||
|
||||
for (prev=0 ; prev<256 ; prev++)
|
||||
{
|
||||
memset (cin.h_count,0,sizeof(cin.h_count));
|
||||
memset (cin.h_used,0,sizeof(cin.h_used));
|
||||
|
||||
// read a row of counts
|
||||
fread (counts, 1, sizeof(counts), cin.cinematic_file);
|
||||
for (j=0 ; j<256 ; j++)
|
||||
cin.h_count[j] = counts[j];
|
||||
|
||||
// build the nodes
|
||||
numhnodes = 256;
|
||||
nodebase = cin.hnodes1 + prev*256*2;
|
||||
|
||||
while (numhnodes != 511)
|
||||
{
|
||||
node = nodebase + (numhnodes-256)*2;
|
||||
|
||||
// pick two lowest counts
|
||||
node[0] = SmallestNode1 (numhnodes);
|
||||
if (node[0] == -1)
|
||||
break; // no more
|
||||
|
||||
node[1] = SmallestNode1 (numhnodes);
|
||||
if (node[1] == -1)
|
||||
break;
|
||||
|
||||
cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
|
||||
numhnodes++;
|
||||
}
|
||||
|
||||
cin.numhnodes1[prev] = numhnodes-1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Huff1Decompress
|
||||
==================
|
||||
*/
|
||||
static cblock_t Huff1Decompress (cblock_t in)
|
||||
{
|
||||
qbyte *input;
|
||||
qbyte *out_p;
|
||||
int nodenum;
|
||||
int count;
|
||||
cblock_t out;
|
||||
int inbyte;
|
||||
int *hnodes, *hnodesbase;
|
||||
//int i;
|
||||
|
||||
// get decompressed count
|
||||
count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
|
||||
input = in.data + 4;
|
||||
out_p = out.data = Z_Malloc (count);
|
||||
|
||||
// read bits
|
||||
|
||||
hnodesbase = cin.hnodes1 - 256*2; // nodes 0-255 aren't stored
|
||||
|
||||
hnodes = hnodesbase;
|
||||
nodenum = cin.numhnodes1[0];
|
||||
while (count)
|
||||
{
|
||||
inbyte = *input++;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
}
|
||||
|
||||
if (input - in.data != in.count && input - in.data != in.count+1)
|
||||
{
|
||||
Con_Printf ("Decompression overread by %i", (input - in.data) - in.count);
|
||||
}
|
||||
out.count = out_p - out.data;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_ReadNextFrame
|
||||
==================
|
||||
*/
|
||||
qbyte *CIN_ReadNextFrame (void)
|
||||
{
|
||||
int r;
|
||||
int command;
|
||||
qbyte samples[22050/14*4];
|
||||
qbyte compressed[0x20000];
|
||||
int size;
|
||||
qbyte *pic;
|
||||
cblock_t in, huf1;
|
||||
int start, end, count;
|
||||
|
||||
// read the next frame
|
||||
r = fread (&command, 4, 1, cin.cinematic_file);
|
||||
if (r == 0) // we'll give it one more chance
|
||||
r = fread (&command, 4, 1, cin.cinematic_file);
|
||||
|
||||
if (r != 1)
|
||||
return NULL;
|
||||
command = LittleLong(command);
|
||||
if (command == 2)
|
||||
return NULL; // last frame marker
|
||||
|
||||
if (command == 1)
|
||||
{ // read palette
|
||||
fread (cin.cinematicpalette, 1, sizeof(cin.cinematicpalette), cin.cinematic_file);
|
||||
cin.cinematicpalette_active=0; // dubious.... exposes an edge case
|
||||
}
|
||||
|
||||
// decompress the next frame
|
||||
fread (&size, 1, 4, cin.cinematic_file);
|
||||
size = LittleLong(size);
|
||||
if (size > sizeof(compressed) || size < 1)
|
||||
Host_Error ("Bad compressed frame size");
|
||||
fread (compressed, 1, size, cin.cinematic_file);
|
||||
|
||||
// read sound
|
||||
start = cin.cinematicframe*cin.s_rate/14;
|
||||
end = (cin.cinematicframe+1)*cin.s_rate/14;
|
||||
count = end - start;
|
||||
|
||||
fread (samples, 1, count*cin.s_width*cin.s_channels, cin.cinematic_file);
|
||||
|
||||
S_RawAudio (0, samples, cin.s_rate, count, cin.s_channels, cin.s_width);
|
||||
|
||||
in.data = compressed;
|
||||
in.count = size;
|
||||
|
||||
huf1 = Huff1Decompress (in);
|
||||
|
||||
pic = huf1.data;
|
||||
|
||||
cin.cinematicframe++;
|
||||
|
||||
return pic;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_RunCinematic
|
||||
|
||||
==================
|
||||
*/
|
||||
qboolean CIN_DrawCinematic (void);
|
||||
qboolean CIN_RunCinematic (void)
|
||||
{
|
||||
int frame;
|
||||
|
||||
if (cin.cinematictime <= 0)
|
||||
{
|
||||
CIN_StopCinematic ();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cin.cinematictime-3 > realtime*1000)
|
||||
cin.cinematictime = realtime*1000;
|
||||
|
||||
/* if (key_dest != key_game)
|
||||
{ // pause if menu or console is up
|
||||
cin.cinematictime = realtime - cin.cinematicframe*1000/14;
|
||||
return true;
|
||||
}*/
|
||||
|
||||
frame = (realtime*1000 - cin.cinematictime)*14/1000;
|
||||
if (frame <= cin.cinematicframe)
|
||||
return true;
|
||||
if (frame > cin.cinematicframe+1)
|
||||
{
|
||||
Con_Printf ("Dropped frame: %i > %i\n", frame, cin.cinematicframe+1);
|
||||
cin.cinematictime = realtime*1000 - cin.cinematicframe*1000/14;
|
||||
}
|
||||
if (cin.pic)
|
||||
Z_Free (cin.pic);
|
||||
cin.pic = cin.pic_pending;
|
||||
cin.pic_pending = NULL;
|
||||
cin.pic_pending = CIN_ReadNextFrame ();
|
||||
if (!cin.pic_pending)
|
||||
{
|
||||
CIN_StopCinematic ();
|
||||
CIN_FinishCinematic ();
|
||||
cin.cinematictime = 1; // hack to get the black screen behind loading
|
||||
SCR_BeginLoadingPlaque ();
|
||||
cin.cinematictime = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_DrawCinematic
|
||||
|
||||
Returns true if a cinematic is active, meaning the view rendering
|
||||
should be skipped
|
||||
==================
|
||||
*/
|
||||
qboolean CIN_DrawCinematic (void)
|
||||
{
|
||||
if (cin.cinematictime <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key_dest == key_menu)
|
||||
{ // blank screen and pause if menu is up
|
||||
// re.CinematicSetPalette(NULL);
|
||||
cin.cinematicpalette_active = false;
|
||||
// return true;
|
||||
}
|
||||
|
||||
if (!cin.cinematicpalette_active)
|
||||
{
|
||||
// re.CinematicSetPalette(cl.cinematicpalette);
|
||||
cin.cinematicpalette_active = true;
|
||||
}
|
||||
|
||||
if (!cin.pic)
|
||||
return true;
|
||||
|
||||
|
||||
Media_ShowFrame8bit(cin.pic, cin.width, cin.height, cin.cinematicpalette);
|
||||
|
||||
// re.DrawStretchRaw (0, 0, viddef.width, viddef.height,
|
||||
// cin.width, cin.height, cin.pic);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_PlayCinematic
|
||||
|
||||
==================
|
||||
*/
|
||||
qboolean CIN_PlayCinematic (char *arg)
|
||||
{
|
||||
int width, height;
|
||||
char name[MAX_OSPATH];
|
||||
// int old_khz;
|
||||
|
||||
// make sure CD isn't playing music
|
||||
CDAudio_Stop();
|
||||
|
||||
cin.cinematicframe = 0;
|
||||
|
||||
COM_FOpenFile (arg, &cin.cinematic_file);
|
||||
if (!cin.cinematic_file)
|
||||
{
|
||||
_snprintf (name, sizeof(name), "video/%s", arg);
|
||||
COM_FOpenFile (name, &cin.cinematic_file);
|
||||
}
|
||||
if (!cin.cinematic_file)
|
||||
{
|
||||
// Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
|
||||
CIN_FinishCinematic ();
|
||||
cin.cinematictime = 0; // done
|
||||
return true;
|
||||
}
|
||||
|
||||
SCR_EndLoadingPlaque ();
|
||||
|
||||
fread (&width, 1, 4, cin.cinematic_file);
|
||||
fread (&height, 1, 4, cin.cinematic_file);
|
||||
cin.width = LittleLong(width);
|
||||
cin.height = LittleLong(height);
|
||||
|
||||
fread (&cin.s_rate, 1, 4, cin.cinematic_file);
|
||||
cin.s_rate = LittleLong(cin.s_rate);
|
||||
fread (&cin.s_width, 1, 4, cin.cinematic_file);
|
||||
cin.s_width = LittleLong(cin.s_width);
|
||||
fread (&cin.s_channels, 1, 4, cin.cinematic_file);
|
||||
cin.s_channels = LittleLong(cin.s_channels);
|
||||
|
||||
Huff1TableInit ();
|
||||
|
||||
// switch up to 22 khz sound if necessary
|
||||
/*old_khz = Cvar_VariableValue ("snd_khz");
|
||||
if (old_khz != cin.s_rate/1000)
|
||||
{
|
||||
cin.restart_sound = true;
|
||||
Cvar_SetValue ("snd_khz", cin.s_rate/1000);
|
||||
S_Restart_f ();
|
||||
Cvar_SetValue ("snd_khz", old_khz);
|
||||
}*/
|
||||
|
||||
cin.cinematicframe = 0;
|
||||
cin.pic = CIN_ReadNextFrame ();
|
||||
cin.cinematictime = Sys_DoubleTime ()*1000;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,356 @@
|
|||
//Config for Crosshairs
|
||||
//crosshairs can be altered or added by editing only this file
|
||||
|
||||
//winquake calls this every frame.
|
||||
//gl calls when changed or animating (that's the diference in animated and non animated)
|
||||
|
||||
//don't use a point more than 8 units away from the centre.
|
||||
//default must be non animated
|
||||
|
||||
#ifdef NUMCROSSHAIRS
|
||||
|
||||
//case 0 is no cursor
|
||||
//case 1 is the console text '+'
|
||||
//neither use this file.
|
||||
|
||||
case 2:
|
||||
Pix(0 - 1, 0, c);
|
||||
Pix(0 - 3, 0, c2);
|
||||
Pix(0 + 1, 0, c);
|
||||
Pix(0 + 3, 0, c2);
|
||||
Pix(0, 0 - 1, c);
|
||||
Pix(0, 0 - 3, c2);
|
||||
Pix(0, 0 + 1, c);
|
||||
Pix(0, 0 + 3, c2);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
Pix(0 - 1, 0, c);
|
||||
Pix(0 - 2, 0, c2);
|
||||
Pix(0 + 1, 0, c);
|
||||
Pix(0 + 2, 0, c2);
|
||||
Pix(0, 0 - 1, c);
|
||||
Pix(0, 0 - 2, c2);
|
||||
Pix(0, 0 + 1, c);
|
||||
Pix(0, 0 + 2, c2);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
Pix(0-1, 0-1, c);
|
||||
Pix(0-2, 0-2, c2);
|
||||
Pix(0+1, 0+1, c);
|
||||
Pix(0+2, 0+2, c2);
|
||||
Pix(0-1, 0+1, c);
|
||||
Pix(0-2, 0+2, c2);
|
||||
Pix(0+1, 0-1, c);
|
||||
Pix(0+2, 0-2, c2);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
Pix(0-1, 0-1, c);
|
||||
Pix(0-3, 0-3, c2);
|
||||
Pix(0+1, 0+1, c);
|
||||
Pix(0+3, 0+3, c2);
|
||||
Pix(0-1, 0+1, c);
|
||||
Pix(0-3, 0+3, c2);
|
||||
Pix(0+1, 0-1, c);
|
||||
Pix(0+3, 0-3, c2);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
Pix(0-1, 0-2, c2);
|
||||
Pix(0+1, 0-2, c2);
|
||||
Pix(0-1, 0+2, c2);
|
||||
Pix(0+1, 0+2, c2);
|
||||
Pix(0-2, 0+1, c);
|
||||
Pix(0-2, 0-1, c);
|
||||
Pix(0+2, 0+1, c);
|
||||
Pix(0+2, 0-1, c);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
Pix(0 , 0+2, c);
|
||||
Pix(0+1, 0+1, c2);
|
||||
Pix(0+2, 0 , c);
|
||||
Pix(0+1, 0-1, c2);
|
||||
Pix(0 , 0-2, c);
|
||||
Pix(0-1, 0-1, c2);
|
||||
Pix(0-2, 0 , c);
|
||||
Pix(0-1, 0+1, c2);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
Pix(0 , 0+2, c);
|
||||
Pix(0 , 0-2, c);
|
||||
Pix(0+2, 0 , c2);
|
||||
Pix(0-2, 0 , c2);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
Pix(0 , 0-1, c);
|
||||
Pix(0-2, 0+1, c2);
|
||||
Pix(0+2, 0+1, c2);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
Pix(0 , 0-3, c);
|
||||
Pix(0-2, 0-2, c2);
|
||||
Pix(0 , 0-2, c);
|
||||
Pix(0+2, 0-2, c2);
|
||||
Pix(0-3, 0 , c);
|
||||
Pix(0-2, 0 , c);
|
||||
Pix(0+2, 0 , c);
|
||||
Pix(0+3, 0 , c);
|
||||
Pix(0 , 0+3, c);
|
||||
Pix(0-2, 0+2, c2);
|
||||
Pix(0 , 0+2, c);
|
||||
Pix(0+2, 0+2, c2);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
Pix(0-3, 0-3, c2);
|
||||
Pix(0 , 0-3, c);
|
||||
Pix(0+3, 0-3, c2);
|
||||
Pix(0-2, 0-2, c2);
|
||||
Pix(0 , 0-2, c);
|
||||
Pix(0+2, 0-2, c2);
|
||||
Pix(0-3, 0 , c);
|
||||
Pix(0-2, 0 , c);
|
||||
Pix(0+2, 0 , c);
|
||||
Pix(0+3, 0 , c);
|
||||
Pix(0 , 0+3, c);
|
||||
Pix(0-2, 0+2, c2);
|
||||
Pix(0 , 0+2, c);
|
||||
Pix(0-3, 0+3, c2);
|
||||
Pix(0+2, 0+2, c2);
|
||||
Pix(0+3, 0+3, c2);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
Pix(0-4, 0 , c2);
|
||||
Pix(0-3, 0 , c2);
|
||||
Pix(0-2, 0 , c);
|
||||
Pix(0-1, 0 , c);
|
||||
Pix(0+1, 0 , c);
|
||||
Pix(0+2, 0 , c);
|
||||
Pix(0+3, 0 , c2);
|
||||
Pix(0+4, 0 , c2);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
Pix(0 , 0-4, c2);
|
||||
Pix(0 , 0-3, c2);
|
||||
Pix(0 , 0-2, c);
|
||||
Pix(0 , 0-1, c);
|
||||
Pix(0 , 0+1, c);
|
||||
Pix(0 , 0+2, c);
|
||||
Pix(0 , 0+3, c2);
|
||||
Pix(0 , 0+4, c2);
|
||||
break;
|
||||
|
||||
case 14:
|
||||
Pix(0-4, 0 , c2);
|
||||
Pix(0-3, 0 , c2);
|
||||
Pix(0-2, 0 , c);
|
||||
Pix(0-1, 0 , c);
|
||||
Pix(0+1, 0 , c);
|
||||
Pix(0+2, 0 , c);
|
||||
Pix(0+3, 0 , c2);
|
||||
Pix(0+4, 0 , c2);
|
||||
|
||||
Pix(0 , 0-4, c2);
|
||||
Pix(0 , 0-3, c2);
|
||||
Pix(0 , 0-2, c);
|
||||
Pix(0 , 0-1, c);
|
||||
Pix(0 , 0+1, c);
|
||||
Pix(0 , 0+2, c);
|
||||
Pix(0 , 0+3, c2);
|
||||
Pix(0 , 0+4, c2);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
Pix(0 , 0-4, c);
|
||||
Pix(0-3, 0-3, c2);
|
||||
Pix(0 , 0-3, c);
|
||||
Pix(0+3, 0-3, c2);
|
||||
Pix(0-2, 0-2, c2);
|
||||
Pix(0 , 0-2, c);
|
||||
Pix(0+2, 0-2, c2);
|
||||
Pix(0-4, 0 , c);
|
||||
Pix(0-3, 0 , c);
|
||||
Pix(0-2, 0 , c);
|
||||
Pix(0+2, 0 , c);
|
||||
Pix(0+3, 0 , c);
|
||||
Pix(0+4, 0 , c);
|
||||
Pix(0 , 0+3, c);
|
||||
Pix(0-2, 0+2, c2);
|
||||
Pix(0 , 0+2, c);
|
||||
Pix(0-3, 0+3, c2);
|
||||
Pix(0+2, 0+2, c2);
|
||||
Pix(0+3, 0+3, c2);
|
||||
Pix(0 , 0+4, c);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
Pix(0 , 0 , c2);
|
||||
Pix(0+1, 0+1, c);
|
||||
break;
|
||||
|
||||
case 17:
|
||||
Pix(0 , 0 , c);
|
||||
Pix(0 , 1, c2);
|
||||
Pix(0 , 2, c2);
|
||||
Pix( 1, 3, c);
|
||||
Pix( 1, 0 , c2);
|
||||
Pix( 2, 0 , c2);
|
||||
Pix( 3, 1, c);
|
||||
break;
|
||||
|
||||
case 18:
|
||||
Pix(0 , 0 , c);
|
||||
Pix(-2, 0 , c2);
|
||||
Pix(-3, 0 , c2);
|
||||
Pix( 2, 0 , c2);
|
||||
Pix( 3, 0 , c2);
|
||||
Pix(-3, 1 , c2);
|
||||
Pix( 3, 1 , c2);
|
||||
Pix(-3, 2 , c2);
|
||||
Pix( 3, 2 , c2);
|
||||
Pix(-2, 2 , c2);
|
||||
Pix( 2, 2 , c2);
|
||||
Pix(-2, 3 , c2);
|
||||
Pix( 2, 3 , c2);
|
||||
Pix(-1, 3 , c2);
|
||||
Pix( 1, 3 , c2);
|
||||
Pix( 0, 3 , c2);
|
||||
Pix( 0, 4 , c2);
|
||||
break;
|
||||
|
||||
case 19: //tripointer
|
||||
Pix(0 , -1, c); //north
|
||||
Pix(0 , -2, c);
|
||||
Pix(0 , -3, c);
|
||||
|
||||
Pix(1 , 1 , c);
|
||||
Pix(2 , 2 , c);//east
|
||||
Pix(3 , 3 , c);
|
||||
|
||||
Pix(-1, 1 , c);//west
|
||||
Pix(-2, 2 , c);
|
||||
Pix(-3, 3 , c);
|
||||
|
||||
break;
|
||||
|
||||
case 20: //twin circles
|
||||
{
|
||||
#define DEG(a) (a * (3.14 / 180))
|
||||
#define SCLE 8 //don't let it get bigger than 16 wide (+-8)
|
||||
#define SCLE2 4
|
||||
|
||||
int a;
|
||||
#ifndef GLQUAKE
|
||||
for (a = 0; a < 360; a+=5) //softquake doesn't draw as many pixels.
|
||||
#else
|
||||
for (a = 0; a < 360; a+=1) //glquake gets high precision - done less, ya see
|
||||
#endif
|
||||
{
|
||||
Pix((int)(sin(DEG(a)) * SCLE ), (int)(cos(DEG(a)) * SCLE ) , c );
|
||||
Pix((int)(cos(DEG(a)) * SCLE2), (int)(sin(DEG(a)) * SCLE2) , c2);
|
||||
}
|
||||
|
||||
#undef SCLE
|
||||
}
|
||||
break;
|
||||
|
||||
#else
|
||||
//what's the next?
|
||||
#define FIRSTANIMATEDCROSHAIR 21
|
||||
#endif
|
||||
#ifdef NUMCROSSHAIRS
|
||||
|
||||
case FIRSTANIMATEDCROSHAIR: //spinners
|
||||
{
|
||||
#define DEG(a) (a * (3.14 / 180))
|
||||
#define SPEED 6
|
||||
#define SCLE 8 //don't let it get bigger than 16 wide (+-8)
|
||||
#define SCLE2 4
|
||||
#define TIMER realtime
|
||||
Pix((int)(sin(TIMER*SPEED ) * SCLE ), (int)(cos(TIMER*SPEED ) * SCLE ) , c );
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(90 )) * SCLE ), (int)(cos(TIMER*SPEED+DEG(90 )) * SCLE ) , c );
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(180)) * SCLE ), (int)(cos(TIMER*SPEED+DEG(180)) * SCLE ) , c );
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(270)) * SCLE ), (int)(cos(TIMER*SPEED+DEG(270)) * SCLE ) , c );
|
||||
|
||||
Pix((int)(cos(TIMER*SPEED ) * SCLE2), (int)(sin(TIMER*SPEED ) * SCLE2) , c2);
|
||||
Pix((int)(cos(TIMER*SPEED+DEG(90 )) * SCLE2), (int)(sin(TIMER*SPEED+DEG(90 )) * SCLE2) , c2);
|
||||
Pix((int)(cos(TIMER*SPEED+DEG(180)) * SCLE2), (int)(sin(TIMER*SPEED+DEG(180)) * SCLE2) , c2);
|
||||
Pix((int)(cos(TIMER*SPEED+DEG(270)) * SCLE2), (int)(sin(TIMER*SPEED+DEG(270)) * SCLE2) , c2);
|
||||
|
||||
#undef SCLE
|
||||
}
|
||||
break;
|
||||
|
||||
case (FIRSTANIMATEDCROSHAIR+1):
|
||||
{
|
||||
#define DEG(a) (a * (3.14 / 180))
|
||||
#define SPEED 6
|
||||
#define SCLE 4 //don't let it get bigger than 16 wide (+-8)
|
||||
#define TIMER realtime
|
||||
|
||||
Pix((int)(sin(TIMER*SPEED ) * SCLE), (int)(sin(TIMER*SPEED ) * -SCLE) , c );
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(180)) * SCLE), (int)(sin(TIMER*SPEED+DEG(180)) * -SCLE) , c2);
|
||||
|
||||
Pix((int)(cos(TIMER*SPEED ) * SCLE), (int)(cos(TIMER*SPEED ) * SCLE ) , c );
|
||||
Pix((int)(cos(TIMER*SPEED+DEG(180)) * SCLE), (int)(cos(TIMER*SPEED+DEG(180)) * SCLE ) , c2);
|
||||
|
||||
#undef SCLE
|
||||
#undef SPEED
|
||||
}
|
||||
break;
|
||||
|
||||
case (FIRSTANIMATEDCROSHAIR+2):
|
||||
{
|
||||
#define DEG(a) (a * (3.14 / 180))
|
||||
#define SPEED 6
|
||||
#define SCLE 4 //don't let it get bigger than 16 wide (+-8)
|
||||
#define TIMER realtime
|
||||
|
||||
Pix((int)(sin(TIMER*SPEED ) * SCLE), (int)(sin(TIMER*SPEED ) * -SCLE) , c );
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(90)) * SCLE), (int)(sin(TIMER*SPEED+DEG(90)) * -SCLE) , c2);
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(180)) * SCLE), (int)(sin(TIMER*SPEED+DEG(180)) * -SCLE) , c);
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(270)) * SCLE), (int)(sin(TIMER*SPEED+DEG(270)) * -SCLE) , c2);
|
||||
|
||||
Pix((int)(cos(TIMER*SPEED ) * SCLE), (int)(cos(TIMER*SPEED ) * SCLE ) , c );
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(90)) * SCLE), (int)(sin(TIMER*SPEED+DEG(90)) * SCLE) , c2);
|
||||
Pix((int)(cos(TIMER*SPEED+DEG(180)) * SCLE), (int)(cos(TIMER*SPEED+DEG(180)) * SCLE ) , c);
|
||||
Pix((int)(sin(TIMER*SPEED+DEG(270)) * SCLE), (int)(sin(TIMER*SPEED+DEG(270)) * SCLE) , c2);
|
||||
|
||||
#undef SCLE
|
||||
#undef SPEED
|
||||
}
|
||||
break;
|
||||
|
||||
case (FIRSTANIMATEDCROSHAIR+3):
|
||||
{
|
||||
int a;
|
||||
#define DEG(a) (a * (3.14 / 180))
|
||||
#define SPEED 9
|
||||
#define SPEED2 4
|
||||
#define SIZE 8 //don't let it get bigger than 16 wide (+-8)
|
||||
#define SCLE 8
|
||||
#define TIMER realtime
|
||||
|
||||
for (a = -SIZE; a < SIZE; a+=2)
|
||||
{
|
||||
Pix(a, (int)(sin(TIMER*SPEED2) * SCLE), c);
|
||||
Pix((int)(sin(TIMER*SPEED) * SCLE), a, c2);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
#else
|
||||
|
||||
//what did we reach
|
||||
#define NUMCROSSHAIRS FIRSTANIMATEDCROSHAIR+3
|
||||
#define CROSSHAIR_H
|
||||
|
||||
#endif
|
|
@ -0,0 +1,469 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
#define MAX_WEAPONS 64 //fixme: make dynamic.
|
||||
|
||||
typedef enum {
|
||||
//one componant
|
||||
ff_death,
|
||||
ff_suicide,
|
||||
ff_bonusfrag,
|
||||
ff_tkbonus,
|
||||
ff_flagtouch,
|
||||
ff_flagcaps,
|
||||
ff_flagdrops,
|
||||
|
||||
//two componant
|
||||
ff_frags, //must be the first of the two componant
|
||||
ff_fragedby,
|
||||
ff_tkills,
|
||||
ff_tkilledby,
|
||||
} fragfilemsgtypes_t;
|
||||
|
||||
typedef struct statmessage_s {
|
||||
fragfilemsgtypes_t type;
|
||||
int wid;
|
||||
char *msgpart1;
|
||||
char *msgpart2;
|
||||
struct statmessage_s *next;
|
||||
} statmessage_t;
|
||||
|
||||
typedef unsigned short stat;
|
||||
typedef struct {
|
||||
stat totaldeaths;
|
||||
stat totalsuicides;
|
||||
stat totalteamkills;
|
||||
stat totalkills;
|
||||
stat totaltouches;
|
||||
stat totalcaps;
|
||||
stat totaldrops;
|
||||
|
||||
//I was going to keep track of kills with a certain gun - too much memory
|
||||
//track only your own and total weapon kills rather than per client
|
||||
struct wt_s {
|
||||
//these include you.
|
||||
stat kills;
|
||||
stat teamkills;
|
||||
stat suicides;
|
||||
|
||||
stat ownkills;
|
||||
stat owndeaths;
|
||||
stat ownteamkills;
|
||||
stat ownteamdeaths;
|
||||
stat ownsuicides;
|
||||
char *fullname;
|
||||
char *abrev;
|
||||
char *codename;
|
||||
} weapontotals[MAX_WEAPONS];
|
||||
|
||||
struct ct_s {
|
||||
stat caps; //times they captured the flag
|
||||
stat drops; //times lost the flag
|
||||
stat grabs; //times grabbed flag
|
||||
|
||||
stat owndeaths; //times you killed them
|
||||
stat ownkills; //times they killed you
|
||||
stat deaths; //times they died (including by you)
|
||||
stat kills; //times they killed (including by you)
|
||||
stat teamkills; //times they killed a team member.
|
||||
stat teamdeaths; //times they killed a team member.
|
||||
stat suisides; //times they were stupid.
|
||||
} clienttotals[MAX_CLIENTS];
|
||||
|
||||
statmessage_t *message;
|
||||
} fragstats_t;
|
||||
|
||||
static fragstats_t fragstats;
|
||||
|
||||
void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
|
||||
{
|
||||
qboolean u1;
|
||||
qboolean u2;
|
||||
|
||||
if (mt == ff_frags || mt == ff_tkills)
|
||||
{
|
||||
int tmp = p1;
|
||||
p1 = p2;
|
||||
p2 = tmp;
|
||||
}
|
||||
|
||||
u1 = (p1 == (cl.playernum[0]&127));
|
||||
u2 = (p2 == (cl.playernum[0]&127));
|
||||
|
||||
switch(mt)
|
||||
{
|
||||
case ff_death:
|
||||
if (u1)
|
||||
{
|
||||
fragstats.weapontotals[wid].owndeaths++;
|
||||
fragstats.weapontotals[wid].ownkills++;
|
||||
}
|
||||
fragstats.weapontotals[wid].kills++;
|
||||
fragstats.clienttotals[p1].deaths++;
|
||||
fragstats.totaldeaths++;
|
||||
break;
|
||||
case ff_suicide:
|
||||
if (u1)
|
||||
{
|
||||
fragstats.weapontotals[wid].ownsuicides++;
|
||||
fragstats.weapontotals[wid].owndeaths++;
|
||||
fragstats.weapontotals[wid].ownkills++;
|
||||
}
|
||||
fragstats.weapontotals[wid].suicides++;
|
||||
fragstats.weapontotals[wid].kills++;
|
||||
fragstats.clienttotals[p1].suisides++;
|
||||
fragstats.clienttotals[p1].deaths++;
|
||||
fragstats.totalsuicides++;
|
||||
fragstats.totaldeaths++;
|
||||
break;
|
||||
case ff_bonusfrag:
|
||||
if (u1)
|
||||
fragstats.weapontotals[wid].ownkills++;
|
||||
fragstats.weapontotals[wid].kills++;
|
||||
fragstats.clienttotals[p1].kills++;
|
||||
fragstats.totalkills++;
|
||||
break;
|
||||
case ff_tkbonus:
|
||||
if (u1)
|
||||
fragstats.weapontotals[wid].ownkills++;
|
||||
fragstats.weapontotals[wid].kills++;
|
||||
fragstats.clienttotals[p1].kills++;
|
||||
fragstats.totalkills++;
|
||||
|
||||
if (u1)
|
||||
fragstats.weapontotals[wid].ownteamkills++;
|
||||
fragstats.weapontotals[wid].teamkills++;
|
||||
fragstats.clienttotals[p1].teamkills++;
|
||||
fragstats.totalteamkills++;
|
||||
break;
|
||||
case ff_flagtouch:
|
||||
fragstats.clienttotals[p1].grabs++;
|
||||
fragstats.totaltouches++;
|
||||
break;
|
||||
case ff_flagcaps:
|
||||
fragstats.clienttotals[p1].caps++;
|
||||
fragstats.totalcaps++;
|
||||
break;
|
||||
case ff_flagdrops:
|
||||
fragstats.clienttotals[p1].drops++;
|
||||
fragstats.totaldrops++;
|
||||
break;
|
||||
|
||||
//p1 died, p2 killed
|
||||
case ff_frags:
|
||||
case ff_fragedby:
|
||||
fragstats.weapontotals[wid].kills++;
|
||||
|
||||
if (u1)
|
||||
fragstats.weapontotals[wid].owndeaths++;
|
||||
fragstats.clienttotals[p1].deaths++;
|
||||
fragstats.totaldeaths++;
|
||||
|
||||
if (u2)
|
||||
fragstats.weapontotals[wid].ownkills++;
|
||||
fragstats.clienttotals[p2].kills++;
|
||||
fragstats.totalkills++;
|
||||
break;
|
||||
case ff_tkills:
|
||||
case ff_tkilledby:
|
||||
fragstats.weapontotals[wid].teamkills++;
|
||||
fragstats.weapontotals[wid].kills++;
|
||||
|
||||
if (u1)
|
||||
{
|
||||
fragstats.weapontotals[wid].ownteamdeaths++;
|
||||
fragstats.weapontotals[wid].owndeaths++;
|
||||
}
|
||||
fragstats.clienttotals[p1].teamdeaths++;
|
||||
fragstats.clienttotals[p1].deaths++;
|
||||
fragstats.totaldeaths++;
|
||||
|
||||
if (u2)
|
||||
{
|
||||
fragstats.weapontotals[wid].ownkills++;
|
||||
fragstats.weapontotals[wid].ownkills++;
|
||||
}
|
||||
fragstats.clienttotals[p2].teamkills++;
|
||||
fragstats.clienttotals[p2].kills++;
|
||||
fragstats.totalkills++;
|
||||
|
||||
fragstats.totalteamkills++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int Stats_FindWeapon(char *codename, qboolean create)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!strcmp(codename, "NONE"))
|
||||
return 0;
|
||||
if (!strcmp(codename, "NULL"))
|
||||
return 0;
|
||||
if (!strcmp(codename, "NOWEAPON"))
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < MAX_WEAPONS; i++)
|
||||
{
|
||||
if (!fragstats.weapontotals[i].codename)
|
||||
{
|
||||
fragstats.weapontotals[i].codename = Z_Malloc(strlen(codename)+1);
|
||||
strcpy(fragstats.weapontotals[i].codename, codename);
|
||||
return i;
|
||||
}
|
||||
|
||||
if (!stricmp(fragstats.weapontotals[i].codename, codename))
|
||||
{
|
||||
if (create)
|
||||
return -2;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void Stats_StatMessage(fragfilemsgtypes_t type, int wid, char *token1, char *token2)
|
||||
{
|
||||
statmessage_t *ms;
|
||||
char *t;
|
||||
ms = Z_Malloc(sizeof(statmessage_t) + strlen(token1)+1 + (token2 && *token2?strlen(token2)+1:0));
|
||||
t = (char *)(ms+1);
|
||||
ms->msgpart1 = t;
|
||||
strcpy(t, token1);
|
||||
if (token2 && *token2)
|
||||
{
|
||||
t += strlen(t)+1;
|
||||
ms->msgpart2 = t;
|
||||
strcpy(t, token2);
|
||||
}
|
||||
ms->type = type;
|
||||
ms->wid = wid;
|
||||
}
|
||||
|
||||
static void Stats_Clear(void)
|
||||
{
|
||||
int i;
|
||||
statmessage_t *ms;
|
||||
|
||||
while (fragstats.message)
|
||||
{
|
||||
ms = fragstats.message;
|
||||
fragstats.message = ms->next;
|
||||
Z_Free(ms);
|
||||
}
|
||||
|
||||
for (i = 1; i < MAX_WEAPONS; i++)
|
||||
{
|
||||
if (fragstats.weapontotals[i].codename) Z_Free(fragstats.weapontotals[i].codename);
|
||||
if (fragstats.weapontotals[i].fullname) Z_Free(fragstats.weapontotals[i].fullname);
|
||||
if (fragstats.weapontotals[i].abrev) Z_Free(fragstats.weapontotals[i].abrev);
|
||||
}
|
||||
|
||||
memset(&fragstats, 0, sizeof(fragstats));
|
||||
}
|
||||
|
||||
#define Z_Copy(tk) tz = Z_Malloc(strlen(tk)+1);strcpy(tz, tk) //remember the braces
|
||||
|
||||
static void Stats_LoadFragFile(char *name)
|
||||
{
|
||||
char filename[MAX_QPATH];
|
||||
char *file;
|
||||
char *end;
|
||||
char *tk, *tz;
|
||||
|
||||
Stats_Clear();
|
||||
|
||||
strcpy(filename, name);
|
||||
COM_DefaultExtension(filename, ".dat");
|
||||
|
||||
file = COM_LoadTempFile(filename);
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
for (end = file; *end && *end != '\n'; end++)
|
||||
;
|
||||
*end = '\0';
|
||||
if (!*file)
|
||||
break;
|
||||
|
||||
Cmd_TokenizeString(file);
|
||||
file = end+1;
|
||||
if (!Cmd_Argc())
|
||||
continue;
|
||||
|
||||
tk = Cmd_Argv(0);
|
||||
if (!stricmp(tk, "#fragfile"))
|
||||
{
|
||||
tk = Cmd_Argv(1);
|
||||
if (!stricmp(tk, "version")) {}
|
||||
else if (!stricmp(tk, "gamedir")) {}
|
||||
else Con_Printf("Unrecognised #meta \"%s\"\n", tk);
|
||||
}
|
||||
else if (!stricmp(tk, "#meta"))
|
||||
{
|
||||
tk = Cmd_Argv(1);
|
||||
if (!stricmp(tk, "title")) {}
|
||||
else if (!stricmp(tk, "description")) {}
|
||||
else if (!stricmp(tk, "author")) {}
|
||||
else if (!stricmp(tk, "email")) {}
|
||||
else if (!stricmp(tk, "webpage")) {}
|
||||
else {Con_Printf("Unrecognised #meta \"%s\"\n", tk);continue;}
|
||||
}
|
||||
else if (!stricmp(tk, "#define"))
|
||||
{
|
||||
tk = Cmd_Argv(1);
|
||||
if (!stricmp(tk, "weapon_class") ||
|
||||
!stricmp(tk, "wc"))
|
||||
{
|
||||
int wid;
|
||||
|
||||
tk = Cmd_Argv(2);
|
||||
|
||||
wid = Stats_FindWeapon(tk, true);
|
||||
if (wid == -1)
|
||||
{Con_Printf("Too many weapon definitions. The max is %i\n", MAX_WEAPONS);continue;}
|
||||
else if (wid < -1)
|
||||
{Con_Printf("Weapon \"%s\" is already defined\n", tk);continue;}
|
||||
else
|
||||
{
|
||||
fragstats.weapontotals[wid].fullname = Z_Copy(Cmd_Argv(3));
|
||||
fragstats.weapontotals[wid].abrev = Z_Copy(Cmd_Argv(4));
|
||||
}
|
||||
}
|
||||
else if (!stricmp(tk, "obituary") ||
|
||||
!stricmp(tk, "obit"))
|
||||
{
|
||||
int fftype;
|
||||
tk = Cmd_Argv(2);
|
||||
|
||||
if (!stricmp(tk, "PLAYER_DEATH")) {fftype = ff_death;}
|
||||
else if (!stricmp(tk, "PLAYER_SUICIDE")) {fftype = ff_suicide;}
|
||||
else if (!stricmp(tk, "X_FRAGS_UNKNOWN")) {fftype = ff_bonusfrag;}
|
||||
else if (!stricmp(tk, "X_TEAMKILLS_UNKNOWN")) {fftype = ff_tkbonus;}
|
||||
else if (!stricmp(tk, "X_FRAGS_Y")) {fftype = ff_frags;}
|
||||
else if (!stricmp(tk, "X_FRAGGED_BY_Y")) {fftype = ff_fragedby;}
|
||||
else if (!stricmp(tk, "X_TEAMKILLS_Y")) {fftype = ff_tkills;}
|
||||
else if (!stricmp(tk, "X_TEAMKILLED_BY_Y")) {fftype = ff_tkilledby;}
|
||||
else {Con_Printf("Unrecognised obituary \"%s\"\n", tk);continue;}
|
||||
|
||||
Stats_StatMessage(fftype, Stats_FindWeapon(Cmd_Argv(3), false), Cmd_Argv(4), Cmd_Argv(5));
|
||||
}
|
||||
else if (!stricmp(tk, "flag_alert") ||
|
||||
!stricmp(tk, "flag_msg"))
|
||||
{
|
||||
int fftype;
|
||||
tk = Cmd_Argv(2);
|
||||
|
||||
if (!stricmp(tk, "X_TOUCHES_FLAG")) {fftype = ff_flagtouch;}
|
||||
else if (!stricmp(tk, "X_GETS_FLAG")) {fftype = ff_flagtouch;}
|
||||
else if (!stricmp(tk, "X_TAKES_FLAG")) {fftype = ff_flagtouch;}
|
||||
else if (!stricmp(tk, "X_CAPTURES_FLAG")) {fftype = ff_flagcaps;}
|
||||
else if (!stricmp(tk, "X_CAPS_FLAG")) {fftype = ff_flagcaps;}
|
||||
else if (!stricmp(tk, "X_SCORES")) {fftype = ff_flagcaps;}
|
||||
else if (!stricmp(tk, "X_DROPS_FLAG")) {fftype = ff_flagdrops;}
|
||||
else if (!stricmp(tk, "X_FUMBLES_FLAG")) {fftype = ff_flagdrops;}
|
||||
else if (!stricmp(tk, "X_LOSES_FLAG")) {fftype = ff_flagdrops;}
|
||||
else {Con_Printf("Unrecognised flag alert \"%s\"\n", tk);continue;}
|
||||
|
||||
Stats_StatMessage(fftype, 0, Cmd_Argv(3), NULL);
|
||||
}
|
||||
else {Con_Printf("Unrecognised directive \"%s\"\n", tk);continue;}
|
||||
}
|
||||
else {Con_Printf("Unrecognised directive \"%s\"\n", tk);continue;}
|
||||
}
|
||||
}
|
||||
|
||||
int qm_strcmp(char *s1, char *s2)//not like strcmp at all...
|
||||
{
|
||||
while(*s1)
|
||||
{
|
||||
if ((*s1++&0x7f)!=(*s2++&0x7f))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_stricmp(char *s1, char *s2)//not like strcmp at all...
|
||||
{
|
||||
int c1,c2;
|
||||
while(*s1)
|
||||
{
|
||||
c1 = *s1++&0x7f;
|
||||
c2 = *s2++&0x7f;
|
||||
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 = c1 - 'A' + 'a';
|
||||
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 = c2 - 'A' + 'a';
|
||||
|
||||
if (c1!=c2)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int Stats_ExtractName(char **line)
|
||||
{
|
||||
int i;
|
||||
int bm;
|
||||
int ml = 0;
|
||||
int l;
|
||||
bm = -1;
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if (!qm_strcmp(cl.players[i].name, *line))
|
||||
{
|
||||
l = strlen(cl.players[i].name);
|
||||
if (l > ml)
|
||||
{
|
||||
bm = i;
|
||||
ml = l;
|
||||
}
|
||||
}
|
||||
}
|
||||
*line += ml;
|
||||
return bm;
|
||||
}
|
||||
|
||||
void Stats_ParsePrintLine(char *line)
|
||||
{
|
||||
statmessage_t *ms;
|
||||
int p1;
|
||||
int p2;
|
||||
char *m2;
|
||||
|
||||
p1 = Stats_ExtractName(&line);
|
||||
if (p1<0) //reject it.
|
||||
return;
|
||||
|
||||
for (ms = fragstats.message; ms; ms = ms->next)
|
||||
{
|
||||
if (!qm_stricmp(ms->msgpart1, line))
|
||||
{
|
||||
if (ms->type >= ff_frags)
|
||||
{ //two players
|
||||
m2 = line + strlen(ms->msgpart1);
|
||||
p2 = Stats_ExtractName(&m2);
|
||||
if (!qm_stricmp(ms->msgpart2, m2))
|
||||
{
|
||||
Stats_Evaluate(ms->type, ms->wid, p1, p2);
|
||||
return; //done.
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //one player
|
||||
Stats_Evaluate(ms->type, ms->wid, p1, p1);
|
||||
return; //done.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Stats_NewMap(void)
|
||||
{
|
||||
Stats_LoadFragFile("fragfile");
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// input.h -- external (non-keyboard) input devices
|
||||
|
||||
void IN_Init (void);
|
||||
|
||||
void IN_Shutdown (void);
|
||||
|
||||
void IN_Commands (void);
|
||||
// oportunity for devices to stick commands on the script buffer
|
||||
|
||||
void IN_Move (usercmd_t *cmd, int pnum);
|
||||
// add additional movement on top of the keyboard move cmd
|
||||
|
||||
void IN_ModeChanged (void);
|
||||
// called whenever screen dimensions change
|
||||
|
||||
void IN_ClearStates (void);
|
||||
void IN_Accumulate (void);
|
||||
#ifdef IN_XFLIP
|
||||
extern cvar_t in_xflip;
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// these are the key numbers that should be passed to Key_Event
|
||||
//
|
||||
enum {
|
||||
K_TAB = 9,
|
||||
K_ENTER = 13,
|
||||
K_ESCAPE = 27,
|
||||
K_SPACE = 32,
|
||||
|
||||
// normal keys should be passed as lowercased ascii
|
||||
|
||||
K_BACKSPACE = 127,
|
||||
|
||||
|
||||
K_SCRLCK,
|
||||
K_CAPSLOCK,
|
||||
K_POWER,
|
||||
K_PAUSE,
|
||||
|
||||
K_UPARROW,
|
||||
K_DOWNARROW,
|
||||
K_LEFTARROW,
|
||||
K_RIGHTARROW,
|
||||
|
||||
K_ALT,
|
||||
K_CTRL,
|
||||
K_SHIFT,
|
||||
K_INS,
|
||||
K_DEL,
|
||||
K_PGDN,
|
||||
K_PGUP,
|
||||
K_HOME,
|
||||
K_END,
|
||||
|
||||
K_F1,
|
||||
K_F2,
|
||||
K_F3,
|
||||
K_F4,
|
||||
K_F5,
|
||||
K_F6,
|
||||
K_F7,
|
||||
K_F8,
|
||||
K_F9,
|
||||
K_F10,
|
||||
K_F11,
|
||||
K_F12,
|
||||
K_F13,
|
||||
K_F14,
|
||||
K_F15,
|
||||
|
||||
K_KP_HOME,
|
||||
K_KP_UPARROW,
|
||||
K_KP_PGUP,
|
||||
K_KP_LEFTARROW,
|
||||
K_KP_5,
|
||||
K_KP_RIGHTARROW,
|
||||
K_KP_END,
|
||||
K_KP_DOWNARROW,
|
||||
K_KP_PGDN,
|
||||
K_KP_ENTER,
|
||||
K_KP_INS,
|
||||
K_KP_DEL,
|
||||
K_KP_SLASH,
|
||||
K_KP_MINUS,
|
||||
K_KP_PLUS,
|
||||
K_KP_NUMLOCK,
|
||||
K_KP_STAR,
|
||||
K_KP_EQUALS,
|
||||
|
||||
//
|
||||
// mouse buttons generate virtual keys
|
||||
//
|
||||
K_MOUSE1,
|
||||
K_MOUSE2,
|
||||
K_MOUSE3,
|
||||
K_MOUSE4,
|
||||
K_MOUSE5,
|
||||
|
||||
#define K_MOUSE6 K_AUX1
|
||||
#define K_MOUSE7 K_AUX2
|
||||
#define K_MOUSE8 K_AUX3
|
||||
|
||||
// JACK: Intellimouse(c) Mouse Wheel Support
|
||||
K_MWHEELUP,
|
||||
K_MWHEELDOWN,
|
||||
|
||||
//
|
||||
// joystick buttons
|
||||
//
|
||||
K_JOY1 = 203,
|
||||
K_JOY2 = 204,
|
||||
K_JOY3 = 205,
|
||||
K_JOY4 = 206,
|
||||
|
||||
//
|
||||
// aux keys are for multi-buttoned joysticks to generate so they can use
|
||||
// the normal binding process
|
||||
//
|
||||
K_AUX1 = 207,
|
||||
K_AUX2 = 208,
|
||||
K_AUX3 = 209,
|
||||
K_AUX4 = 210,
|
||||
K_AUX5 = 211,
|
||||
K_AUX6 = 212,
|
||||
K_AUX7 = 213,
|
||||
K_AUX8 = 214,
|
||||
K_AUX9 = 215,
|
||||
K_AUX10 = 216,
|
||||
K_AUX11 = 217,
|
||||
K_AUX12 = 218,
|
||||
K_AUX13 = 219,
|
||||
K_AUX14 = 220,
|
||||
K_AUX15 = 221,
|
||||
K_AUX16 = 222,
|
||||
K_AUX17 = 223,
|
||||
K_AUX18 = 224,
|
||||
K_AUX19 = 225,
|
||||
K_AUX20 = 226,
|
||||
K_AUX21 = 227,
|
||||
K_AUX22 = 228,
|
||||
K_AUX23 = 229,
|
||||
K_AUX24 = 230,
|
||||
K_AUX25 = 231,
|
||||
K_AUX26 = 232,
|
||||
K_AUX27 = 233,
|
||||
K_AUX28 = 234,
|
||||
K_AUX29 = 235,
|
||||
K_AUX30 = 236,
|
||||
K_AUX31 = 237,
|
||||
K_AUX32 = 238,
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef enum {key_game, key_console, key_message, key_menu, key_editor} keydest_t;
|
||||
|
||||
extern keydest_t key_dest;
|
||||
extern char *keybindings[256][8];
|
||||
extern int key_repeats[256];
|
||||
extern int key_count; // incremented every key event
|
||||
extern int key_lastpress;
|
||||
|
||||
extern char chat_buffer[];
|
||||
extern int chat_bufferlen;
|
||||
extern qboolean chat_team;
|
||||
|
||||
void Key_Event (int key, qboolean down);
|
||||
void Key_Init (void);
|
||||
void Key_WriteBindings (FILE *f);
|
||||
void Key_SetBinding (int keynum, int modifier, char *binding, int cmdlevel);
|
||||
void Key_ClearStates (void);
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,800 @@
|
|||
#include "bothdefs.h"
|
||||
|
||||
#ifdef CL_MASTER
|
||||
#include "quakedef.h"
|
||||
#include "cl_master.h"
|
||||
|
||||
enum {
|
||||
SLISTTYPE_SERVERS,
|
||||
SLISTTYPE_FAVORITES,
|
||||
SLISTTYPE_SOURCES,
|
||||
SLISTTYPE_OPTIONS //must be last
|
||||
} slist_option;
|
||||
|
||||
int slist_numoptions;
|
||||
int slist_firstoption;
|
||||
|
||||
int slist_type;
|
||||
|
||||
//filtering
|
||||
cvar_t sb_hideempty = {"sb_hideempty", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_hidenotempty = {"sb_hidenotempty", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_hidefull = {"sb_hidefull", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_hidedead = {"sb_hidedead", "1", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_hidequake2 = {"sb_hidequake2", "1", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_hidenetquake = {"sb_hidenetquake", "1", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_hidequakeworld = {"sb_hidequakeworld", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_maxping = {"sb_maxping", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_gamedir = {"sb_gamedir", "", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_mapname = {"sb_mapname", "", NULL, CVAR_ARCHIVE};
|
||||
|
||||
cvar_t sb_showping = {"sb_showping", "1", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_showaddress = {"sb_showaddress", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_showmap = {"sb_showmap", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_showgamedir = {"sb_showgamedir", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_showplayers = {"sb_showplayers", "1", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_showfraglimit = {"sb_showfraglimit", "0", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_showtimelimit = {"sb_showtimelimit", "0", NULL, CVAR_ARCHIVE};
|
||||
|
||||
cvar_t sb_filterkey = {"sb_filterkey", "hostname", NULL, CVAR_ARCHIVE};
|
||||
cvar_t sb_filtervalue = {"sb_filtervalue", "", NULL, CVAR_ARCHIVE};
|
||||
|
||||
void M_Serverlist_Init(void)
|
||||
{
|
||||
char *grp = "Server Browser Vars";
|
||||
|
||||
Cvar_Register(&sb_hideempty, grp);
|
||||
Cvar_Register(&sb_hidenotempty, grp);
|
||||
Cvar_Register(&sb_hidefull, grp);
|
||||
Cvar_Register(&sb_hidedead, grp);
|
||||
Cvar_Register(&sb_hidequake2, grp);
|
||||
Cvar_Register(&sb_hidenetquake, grp);
|
||||
Cvar_Register(&sb_hidequakeworld, grp);
|
||||
|
||||
Cvar_Register(&sb_maxping, grp);
|
||||
Cvar_Register(&sb_gamedir, grp);
|
||||
Cvar_Register(&sb_mapname, grp);
|
||||
|
||||
Cvar_Register(&sb_showping, grp);
|
||||
Cvar_Register(&sb_showaddress, grp);
|
||||
Cvar_Register(&sb_showmap, grp);
|
||||
Cvar_Register(&sb_showgamedir, grp);
|
||||
Cvar_Register(&sb_showplayers, grp);
|
||||
Cvar_Register(&sb_showfraglimit, grp);
|
||||
Cvar_Register(&sb_showtimelimit, grp);
|
||||
}
|
||||
|
||||
|
||||
static void NM_DrawColouredCharacter (int cx, int line, unsigned int num)
|
||||
{
|
||||
Draw_ColouredCharacter(cx, line, num);
|
||||
}
|
||||
static void NM_Print (int cx, int cy, qbyte *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
Draw_ColouredCharacter (cx, cy, (*str)|128);
|
||||
str++;
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void NM_PrintWhite (int cx, int cy, qbyte *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
Draw_ColouredCharacter (cx, cy, (*str));
|
||||
str++;
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void NM_PrintColoured (int cx, int cy, int colour, qbyte *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
NM_DrawColouredCharacter (cx, cy, (*str) + (colour<<8));
|
||||
str++;
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
qboolean M_IsFiltered(serverinfo_t *server) //figure out if we should filter a server.
|
||||
{
|
||||
if (slist_type == SLISTTYPE_FAVORITES)
|
||||
if (!(server->special & SS_FAVORITE))
|
||||
return true;
|
||||
#ifdef Q2CLIENT
|
||||
if (sb_hidequake2.value)
|
||||
#endif
|
||||
if (server->special & SS_QUAKE2)
|
||||
return true;
|
||||
#ifdef NQPROT
|
||||
if (sb_hidenetquake.value)
|
||||
#endif
|
||||
if (server->special & SS_NETQUAKE)
|
||||
return true;
|
||||
if (sb_hidequakeworld.value)
|
||||
if (!(server->special & (SS_QUAKE2|SS_NETQUAKE)))
|
||||
return true;
|
||||
if (sb_hideempty.value)
|
||||
if (!server->players)
|
||||
return true;
|
||||
if (sb_hidenotempty.value)
|
||||
if (server->players)
|
||||
return true;
|
||||
if (sb_hidefull.value)
|
||||
if (server->players == server->maxplayers)
|
||||
return true;
|
||||
if (sb_hidedead.value)
|
||||
if (server->maxplayers == 0)
|
||||
return true;
|
||||
if (sb_maxping.value)
|
||||
if (server->ping > sb_maxping.value)
|
||||
return true;
|
||||
if (*sb_gamedir.string)
|
||||
if (strcmp(server->gamedir, sb_gamedir.string))
|
||||
return true;
|
||||
if (*sb_mapname.string)
|
||||
if (!strstr(server->map, sb_mapname.string))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean M_MasterIsFiltered(master_t *mast)
|
||||
{
|
||||
#ifndef Q2CLIENT
|
||||
if (mast->type == MT_BCASTQ2 || mast->type == MT_SINGLEQ2 || mast->type == MT_MASTERQ2)
|
||||
return true;
|
||||
#endif
|
||||
#ifndef NQPROT
|
||||
if (mast->type == MT_BCASTNQ || mast->type == MT_SINGLENQ)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void M_DrawOneServer (int inity)
|
||||
{
|
||||
char key[512];
|
||||
char value[512];
|
||||
char *o;
|
||||
int l, i;
|
||||
char *s;
|
||||
|
||||
int miny=8*5;
|
||||
int y=8*(5-selectedserver.linenum);
|
||||
|
||||
miny += inity;
|
||||
y += inity;
|
||||
|
||||
if (!selectedserver.detail)
|
||||
{
|
||||
NM_Print (0, y, "No details\n");
|
||||
return;
|
||||
}
|
||||
|
||||
s = selectedserver.detail->info;
|
||||
|
||||
if (*s == '\\')
|
||||
s++;
|
||||
while (*s)
|
||||
{
|
||||
o = key;
|
||||
while (*s && *s != '\\')
|
||||
*o++ = *s++;
|
||||
|
||||
l = o - key;
|
||||
// if (l < 20)
|
||||
// {
|
||||
// memset (o, ' ', 20-l);
|
||||
// key[20] = 0;
|
||||
// }
|
||||
// else
|
||||
*o = 0;
|
||||
if (y>=miny)
|
||||
NM_Print (0, y, va("%19s", key));
|
||||
|
||||
if (!*s)
|
||||
{
|
||||
if (y>=miny)
|
||||
NM_Print (0, y, "MISSING VALUE\n");
|
||||
return;
|
||||
}
|
||||
|
||||
o = value;
|
||||
s++;
|
||||
while (*s && *s != '\\')
|
||||
*o++ = *s++;
|
||||
*o = 0;
|
||||
|
||||
if (*s)
|
||||
s++;
|
||||
if (y>=miny)
|
||||
NM_Print (320/2, y, va("%s\n", value));
|
||||
|
||||
y+=8;
|
||||
}
|
||||
|
||||
for ( i = 0; i < selectedserver.detail->numplayers; i++)
|
||||
{
|
||||
if (y>=miny)
|
||||
{
|
||||
Draw_Fill (12, y, 28, 4, Sbar_ColorForMap(selectedserver.detail->players[i].topc));
|
||||
Draw_Fill (12, y+4, 28, 4, Sbar_ColorForMap(selectedserver.detail->players[i].botc));
|
||||
NM_PrintWhite (12, y, va("%3i", selectedserver.detail->players[i].frags));
|
||||
NM_Print (12+8*4, y, selectedserver.detail->players[i].name);
|
||||
}
|
||||
y+=8;
|
||||
}
|
||||
|
||||
if (y<=miny) //whoops, there was a hole at the end, try scrolling up.
|
||||
selectedserver.linenum--;
|
||||
}
|
||||
|
||||
int M_AddColumn (int right, int y, char *text, int maxchars, int colour)
|
||||
{
|
||||
int left;
|
||||
left = right - maxchars*8;
|
||||
if (left < 0)
|
||||
return right;
|
||||
|
||||
right = left;
|
||||
while (*text && maxchars>0)
|
||||
{
|
||||
NM_DrawColouredCharacter (right, y, (*(unsigned char *)text) + (colour<<8));
|
||||
text++;
|
||||
right += 8;
|
||||
maxchars--;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
void M_DrawServerList(void)
|
||||
{
|
||||
serverinfo_t *server;
|
||||
int op=0, filtered=0;
|
||||
int snum=0;
|
||||
int blink = 0;
|
||||
int colour;
|
||||
|
||||
int x;
|
||||
int y = 8*3;
|
||||
|
||||
CL_QueryServers();
|
||||
|
||||
slist_numoptions = 0;
|
||||
|
||||
//find total servers.
|
||||
for (server = firstserver; server; server = server->next)
|
||||
if (M_IsFiltered(server))
|
||||
filtered++;
|
||||
else
|
||||
slist_numoptions++;
|
||||
|
||||
if (!slist_numoptions)
|
||||
{
|
||||
char *text, *text2="", *text3="";
|
||||
if (filtered)
|
||||
{
|
||||
if (slist_type == SLISTTYPE_FAVORITES)
|
||||
{
|
||||
text = "Highlight a server";
|
||||
text2 = "and press \'f\'";
|
||||
text3 = "to add it to this list";
|
||||
}
|
||||
else
|
||||
text = "All servers were filtered out";
|
||||
}
|
||||
else
|
||||
text = "No servers found";
|
||||
NM_PrintColoured((vid.width-strlen(text)*8)/2, 8*5, 0, text);
|
||||
NM_PrintColoured((vid.width-strlen(text2)*8)/2, 8*5+8, 0, text2);
|
||||
NM_PrintColoured((vid.width-strlen(text3)*8)/2, 8*5+16, 0, text3);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (slist_option >= slist_numoptions)
|
||||
slist_option = slist_numoptions-1;
|
||||
op = vid.height/2/8;
|
||||
op/=2;
|
||||
op=slist_option-op;
|
||||
snum = op;
|
||||
|
||||
|
||||
if (selectedserver.inuse == true)
|
||||
{
|
||||
M_DrawOneServer(8*5);
|
||||
return;
|
||||
}
|
||||
|
||||
if (op < 0)
|
||||
op = 0;
|
||||
if (snum < 0)
|
||||
snum = 0;
|
||||
//find the server that we want
|
||||
for (server = firstserver; op>0; server=server->next)
|
||||
{
|
||||
if (M_IsFiltered(server))
|
||||
continue;
|
||||
op--;
|
||||
}
|
||||
|
||||
y = 8*2;
|
||||
x = vid.width;
|
||||
if (sb_showtimelimit.value)
|
||||
x = M_AddColumn(x, y, "tl", 3, 1);
|
||||
if (sb_showfraglimit.value)
|
||||
x = M_AddColumn(x, y, "fl", 3, 1);
|
||||
if (sb_showplayers.value)
|
||||
x = M_AddColumn(x, y, "plyrs", 6, 1);
|
||||
if (sb_showmap.value)
|
||||
x = M_AddColumn(x, y, "map", 9, 1);
|
||||
if (sb_showgamedir.value)
|
||||
x = M_AddColumn(x, y, "gamedir", 9, 1);
|
||||
if (sb_showping.value)
|
||||
x = M_AddColumn(x, y, "png", 4, 1);
|
||||
if (sb_showaddress.value)
|
||||
x = M_AddColumn(x, y, "address", 21, 1);
|
||||
x = M_AddColumn(x, y, "name", x/8-1, 1);
|
||||
|
||||
y = 8*3;
|
||||
while(server)
|
||||
{
|
||||
if (M_IsFiltered(server))
|
||||
{
|
||||
server = server->next;
|
||||
continue; //doesn't count
|
||||
}
|
||||
|
||||
if (y > vid.height/2)
|
||||
break;
|
||||
|
||||
if (slist_option == snum)
|
||||
blink = (int)(realtime*3)&1;
|
||||
if (*server->name)
|
||||
{
|
||||
if (blink)
|
||||
colour = 6;
|
||||
else if (server->special & SS_FAVORITE)
|
||||
colour = 2;
|
||||
else if (server->special & SS_FTESERVER)
|
||||
colour = 1;
|
||||
else if (server->special & SS_QUAKE2)
|
||||
colour = 3;
|
||||
else if (server->special & SS_NETQUAKE)
|
||||
colour = 5;
|
||||
else
|
||||
colour = 0;
|
||||
|
||||
x = vid.width;
|
||||
|
||||
if (sb_showtimelimit.value)
|
||||
x = M_AddColumn(x, y, va("%i", server->tl), 3, colour); //time limit
|
||||
if (sb_showfraglimit.value)
|
||||
x = M_AddColumn(x, y, va("%i", server->fl), 3, colour); //frag limit
|
||||
if (sb_showplayers.value)
|
||||
x = M_AddColumn(x, y, va("%i/%i", server->players, server->maxplayers), 6, colour);
|
||||
if (sb_showmap.value)
|
||||
x = M_AddColumn(x, y, server->map, 9, colour);
|
||||
if (sb_showgamedir.value)
|
||||
x = M_AddColumn(x, y, server->gamedir, 9, colour);
|
||||
if (sb_showping.value)
|
||||
x = M_AddColumn(x, y, va("%i", server->ping), 4, colour); //frag limit
|
||||
if (sb_showaddress.value)
|
||||
x = M_AddColumn(x, y, NET_AdrToString(server->adr), 21, colour);
|
||||
x = M_AddColumn(x, y, server->name, x/8-1, colour);
|
||||
}
|
||||
|
||||
blink = 0;
|
||||
if (*server->name)
|
||||
y+=8;
|
||||
|
||||
server = server->next;
|
||||
|
||||
snum++;
|
||||
}
|
||||
|
||||
selectedserver.inuse=2;
|
||||
M_DrawOneServer(vid.height/2-4*8);
|
||||
}
|
||||
|
||||
void M_DrawSources (void)
|
||||
{
|
||||
int blink;
|
||||
int snum=0;
|
||||
int op;
|
||||
int y = 3*8;
|
||||
master_t *mast;
|
||||
|
||||
slist_numoptions = 0;
|
||||
//find total sources.
|
||||
for (mast = master; mast; mast = mast->next)
|
||||
slist_numoptions++;
|
||||
|
||||
if (!slist_numoptions)
|
||||
{
|
||||
char *text;
|
||||
if (0)//filtered)
|
||||
text = "All servers were filtered out\n";
|
||||
else
|
||||
text = "No sources were found\n";
|
||||
NM_PrintColoured((vid.width-strlen(text)*8)/2, 8*5, 0, text);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (slist_option >= slist_numoptions)
|
||||
slist_option = slist_numoptions-1;
|
||||
op=slist_option-vid.height/2/8;
|
||||
snum = op;
|
||||
|
||||
if (op < 0)
|
||||
op = 0;
|
||||
if (snum < 0)
|
||||
snum = 0;
|
||||
//find the server that we want
|
||||
for (mast = master; op>0; mast=mast->next)
|
||||
{
|
||||
if (M_MasterIsFiltered(mast))
|
||||
continue;
|
||||
op--;
|
||||
}
|
||||
|
||||
for (; mast; mast = mast->next)
|
||||
{
|
||||
if (M_MasterIsFiltered(mast))
|
||||
continue;
|
||||
|
||||
if (slist_option == snum)
|
||||
blink = (int)(realtime*3)&1;
|
||||
else
|
||||
blink = 0;
|
||||
|
||||
if (blink)
|
||||
NM_PrintColoured(46, y, 6, va("%s", mast->name)); //blinking.
|
||||
else if (mast->type == MT_MASTERQW || mast->type == MT_MASTERQ2)
|
||||
NM_PrintColoured(46, y, 0, va("%s", mast->name)); //white.
|
||||
#ifdef NQPROT
|
||||
else if (mast->type == MT_SINGLENQ)
|
||||
NM_PrintColoured(46, y, 2, va("%s", mast->name)); //green.
|
||||
#endif
|
||||
else if (mast->type == MT_SINGLEQW || mast->type == MT_SINGLEQ2)
|
||||
NM_PrintColoured(46, y, 2, va("%s", mast->name)); //green.
|
||||
else
|
||||
NM_PrintColoured(46, y, 1, va("%s", mast->name)); //red.
|
||||
y+=8;
|
||||
snum++;
|
||||
}
|
||||
}
|
||||
|
||||
#define NUMSLISTOPTIONS (7+7+3)
|
||||
struct {
|
||||
char *title;
|
||||
cvar_t *cvar;
|
||||
int type;
|
||||
} options[NUMSLISTOPTIONS] = {
|
||||
{"Hide Empty", &sb_hideempty},
|
||||
{"Hide Not Empty", &sb_hidenotempty},
|
||||
{"Hide Full", &sb_hidefull},
|
||||
{"Hide Dead", &sb_hidedead},
|
||||
{"Hide Quake 2", &sb_hidequake2},
|
||||
{"Hide Quake 1", &sb_hidenetquake},
|
||||
{"Hide QuakeWorld", &sb_hidequakeworld},
|
||||
|
||||
{"Show pings", &sb_showping},
|
||||
{"Show Addresses", &sb_showaddress},
|
||||
{"Show map", &sb_showmap},
|
||||
{"Show Game Dir", &sb_showgamedir},
|
||||
{"Show Players", &sb_showplayers},
|
||||
{"Show Fraglimit", &sb_showfraglimit},
|
||||
{"Show Timelimit", &sb_showtimelimit},
|
||||
|
||||
{"Max ping", &sb_maxping, 1},
|
||||
{"GameDir", &sb_gamedir, 2},
|
||||
{"Using map", &sb_mapname, 2}
|
||||
};
|
||||
|
||||
void M_DrawSListOptions (void)
|
||||
{
|
||||
int c;
|
||||
int op;
|
||||
|
||||
slist_numoptions = NUMSLISTOPTIONS;
|
||||
|
||||
for (op = 0; op < NUMSLISTOPTIONS; op++)
|
||||
{
|
||||
if (slist_option == op && (int)(realtime*3)&1)
|
||||
c = 6; //cyan
|
||||
else
|
||||
c = options[op].cvar->value>0 || (*options[op].cvar->string && *options[op].cvar->string != '0');//red if on.
|
||||
switch(options[op].type)
|
||||
{
|
||||
default:
|
||||
NM_PrintColoured(46, op*8+8*3, c, options[op].title);
|
||||
break;
|
||||
case 1:
|
||||
if (!options[op].cvar->value)
|
||||
{
|
||||
NM_PrintColoured(46, op*8+8*3, c, va("%s ", options[op].title));
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
NM_PrintColoured(46, op*8+8*3, c, va("%s %s", options[op].title, options[op].cvar->string));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void M_SListOptions_Key (int key)
|
||||
{
|
||||
if (key == K_UPARROW)
|
||||
{
|
||||
slist_option--;
|
||||
if (slist_option<0)
|
||||
slist_option=0;
|
||||
}
|
||||
else if (key == K_DOWNARROW)
|
||||
{
|
||||
slist_option++;
|
||||
if (slist_option >= slist_numoptions)
|
||||
slist_option = slist_numoptions-1;
|
||||
}
|
||||
|
||||
switch(options[slist_option].type)
|
||||
{
|
||||
default:
|
||||
if (key == K_ENTER)
|
||||
{
|
||||
if (options[slist_option].cvar->value)
|
||||
Cvar_Set(options[slist_option].cvar, "0");
|
||||
else
|
||||
Cvar_Set(options[slist_option].cvar, "1");
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (key >= '0' && key <= '9')
|
||||
Cvar_SetValue(options[slist_option].cvar, options[slist_option].cvar->value*10+key-'0');
|
||||
else if (key == K_DEL)
|
||||
Cvar_SetValue(options[slist_option].cvar, 0);
|
||||
else if (key == K_BACKSPACE)
|
||||
Cvar_SetValue(options[slist_option].cvar, (int)options[slist_option].cvar->value/10);
|
||||
break;
|
||||
case 2:
|
||||
if ((key >= '0' && key <= '9') || (key >= 'a' && key <= 'z') || key == '_')
|
||||
Cvar_Set(options[slist_option].cvar, va("%s%c", options[slist_option].cvar->string, key));
|
||||
else if (key == K_DEL)
|
||||
Cvar_Set(options[slist_option].cvar, "");
|
||||
else if (key == K_BACKSPACE) //FIXME
|
||||
Cvar_Set(options[slist_option].cvar, "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_DrawServers(void)
|
||||
{
|
||||
#define NUMSLISTHEADERS (SLISTTYPE_OPTIONS+1)
|
||||
char *titles[NUMSLISTHEADERS] = {
|
||||
"Servers",
|
||||
"Favorites",
|
||||
"Sources",
|
||||
// "Players",
|
||||
"Options"
|
||||
};
|
||||
int snum=0;
|
||||
|
||||
int width, lofs;
|
||||
|
||||
NET_CheckPollSockets(); //see if we were told something important.
|
||||
|
||||
width = vid.width / NUMSLISTHEADERS;
|
||||
lofs = width/2 - 7*4;
|
||||
for (snum = 0; snum < NUMSLISTHEADERS; snum++)
|
||||
{
|
||||
NM_PrintColoured(width*snum+width/2 - strlen(titles[snum])*4, 0, slist_type==snum, titles[snum]);
|
||||
}
|
||||
NM_PrintColoured(8, 8, 0, "\35");
|
||||
for (snum = 16; snum < vid.width-16; snum+=8)
|
||||
NM_PrintColoured(snum, 8, 0, "\36");
|
||||
NM_PrintColoured(snum, 8, 0, "\37");
|
||||
|
||||
switch(slist_type)
|
||||
{
|
||||
case SLISTTYPE_SERVERS:
|
||||
case SLISTTYPE_FAVORITES:
|
||||
M_DrawServerList();
|
||||
break;
|
||||
case SLISTTYPE_SOURCES:
|
||||
M_DrawSources ();
|
||||
break;
|
||||
case SLISTTYPE_OPTIONS:
|
||||
M_DrawSListOptions ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
serverinfo_t *M_FindCurrentServer(void)
|
||||
{
|
||||
serverinfo_t *server;
|
||||
int op = slist_option;
|
||||
for (server = firstserver; server; server = server->next)
|
||||
{
|
||||
if (M_IsFiltered(server))
|
||||
continue; //doesn't count
|
||||
if (!op--)
|
||||
return server;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
master_t *M_FindCurrentMaster(void)
|
||||
{
|
||||
master_t *mast;
|
||||
int op = slist_option;
|
||||
for (mast = master; mast; mast = mast->next)
|
||||
{
|
||||
if (M_MasterIsFiltered(mast))
|
||||
continue;
|
||||
if (!op--)
|
||||
return mast;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void M_SListKey(int key)
|
||||
{
|
||||
if (key == K_ESCAPE)
|
||||
{
|
||||
// if (selectedserver.inuse)
|
||||
// selectedserver.inuse = false;
|
||||
// else
|
||||
M_Menu_MultiPlayer_f();
|
||||
return;
|
||||
}
|
||||
else if (key == K_LEFTARROW)
|
||||
{
|
||||
slist_type--;
|
||||
if (slist_type<0)
|
||||
slist_type=0;
|
||||
|
||||
selectedserver.linenum--;
|
||||
if (selectedserver.linenum<0)
|
||||
selectedserver.linenum=0;
|
||||
|
||||
slist_numoptions=0;
|
||||
return;
|
||||
}
|
||||
else if (key == K_RIGHTARROW)
|
||||
{
|
||||
slist_type++;
|
||||
if (slist_type>NUMSLISTHEADERS-1)
|
||||
slist_type=NUMSLISTHEADERS-1;
|
||||
|
||||
selectedserver.linenum++;
|
||||
|
||||
slist_numoptions = 0;
|
||||
return;
|
||||
}
|
||||
else if (key == 'q')
|
||||
selectedserver.linenum--;
|
||||
else if (key == 'a')
|
||||
selectedserver.linenum++;
|
||||
|
||||
if (!slist_numoptions)
|
||||
return;
|
||||
|
||||
if (slist_type == SLISTTYPE_OPTIONS)
|
||||
{
|
||||
M_SListOptions_Key(key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_UPARROW)
|
||||
{
|
||||
slist_option--;
|
||||
if (slist_option<0)
|
||||
slist_option=0;
|
||||
|
||||
if (slist_type == SLISTTYPE_SERVERS)
|
||||
SListOptionChanged(M_FindCurrentServer()); //go for these early.
|
||||
}
|
||||
else if (key == K_DOWNARROW)
|
||||
{
|
||||
slist_option++;
|
||||
if (slist_option >= slist_numoptions)
|
||||
slist_option = slist_numoptions-1;
|
||||
|
||||
if (slist_type == SLISTTYPE_SERVERS)
|
||||
SListOptionChanged(M_FindCurrentServer()); //go for these early.
|
||||
}
|
||||
else if (key == K_PGDN)
|
||||
{
|
||||
slist_option+=10;
|
||||
if (slist_option >= slist_numoptions)
|
||||
slist_option = slist_numoptions-1;
|
||||
|
||||
if (slist_type == SLISTTYPE_SERVERS)
|
||||
SListOptionChanged(M_FindCurrentServer()); //go for these early.
|
||||
}
|
||||
else if (key == K_PGUP)
|
||||
{
|
||||
slist_option-=10;
|
||||
if (slist_option<0)
|
||||
slist_option=0;
|
||||
|
||||
if (slist_type == SLISTTYPE_SERVERS)
|
||||
SListOptionChanged(M_FindCurrentServer()); //go for these early.
|
||||
}
|
||||
else if (key == 'r')
|
||||
MasterInfo_Begin();
|
||||
else if (key == K_SPACE)
|
||||
{
|
||||
if (slist_type == SLISTTYPE_SERVERS)
|
||||
{
|
||||
selectedserver.inuse = !selectedserver.inuse;
|
||||
if (selectedserver.inuse)
|
||||
SListOptionChanged(M_FindCurrentServer());
|
||||
}
|
||||
}
|
||||
else if (key == 'f')
|
||||
{
|
||||
serverinfo_t *server;
|
||||
if (slist_type == SLISTTYPE_SERVERS) //add to favorites
|
||||
{
|
||||
server = M_FindCurrentServer();
|
||||
if (server)
|
||||
{
|
||||
server->special |= SS_FAVORITE;
|
||||
MasterInfo_WriteServers();
|
||||
}
|
||||
}
|
||||
if (slist_type == SLISTTYPE_FAVORITES) //remove from favorites
|
||||
{
|
||||
server = M_FindCurrentServer();
|
||||
if (server)
|
||||
{
|
||||
server->special &= ~SS_FAVORITE;
|
||||
MasterInfo_WriteServers();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key==K_ENTER)
|
||||
{
|
||||
serverinfo_t *server;
|
||||
if (slist_type == SLISTTYPE_SERVERS || slist_type == SLISTTYPE_FAVORITES)
|
||||
{
|
||||
if (!selectedserver.inuse)
|
||||
{
|
||||
selectedserver.inuse = true;
|
||||
SListOptionChanged(M_FindCurrentServer());
|
||||
return;
|
||||
}
|
||||
server = M_FindCurrentServer();
|
||||
if (!server)
|
||||
return; //ah. off the end.
|
||||
|
||||
if (server->special & SS_NETQUAKE)
|
||||
Cbuf_AddText(va("nqconnect %s\n", NET_AdrToString(server->adr)), RESTRICT_LOCAL);
|
||||
else
|
||||
Cbuf_AddText(va("connect %s\n", NET_AdrToString(server->adr)), RESTRICT_LOCAL);
|
||||
|
||||
M_ToggleMenu_f();
|
||||
M_ToggleMenu_f();
|
||||
}
|
||||
else if (slist_type == SLISTTYPE_SOURCES)
|
||||
{
|
||||
MasterInfo_Request(M_FindCurrentMaster());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,377 @@
|
|||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
|
||||
extern cvar_t maxclients;
|
||||
|
||||
menutext_t *MC_AddWhiteText(menu_t *menu, int x, int y, const char *text, qboolean rightalign);
|
||||
|
||||
/* MULTIPLAYER MENU */
|
||||
void M_Menu_MultiPlayer_f (void)
|
||||
{
|
||||
menubutton_t *b;
|
||||
menu_t *menu;
|
||||
qpic_t *p;
|
||||
|
||||
p = Draw_SafeCachePic("gfx/mp_menu.lmp");
|
||||
if (!p)
|
||||
return; //go q2.
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(0);
|
||||
|
||||
MC_AddPicture(menu, 16, 4, "gfx/qplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_multi.lmp");
|
||||
|
||||
|
||||
MC_AddPicture(menu, 72, 32, "gfx/mp_menu.lmp");
|
||||
|
||||
b = MC_AddConsoleCommand(menu, 72, 32, "", "menu_slist\n");
|
||||
menu->selecteditem = (menuoption_t*)b;
|
||||
b->common.height = 20;
|
||||
b->common.width = p->width;
|
||||
b = MC_AddConsoleCommand(menu, 72, 52, "", "menu_newmulti\n");
|
||||
b->common.height = 20;
|
||||
b->common.width = p->width;
|
||||
b = MC_AddConsoleCommand(menu, 72, 72, "", "menu_setup\n");
|
||||
b->common.height = 20;
|
||||
b->common.width = p->width;
|
||||
|
||||
b = MC_AddConsoleCommand(menu, 72, 92, "", "menu_demo\n");
|
||||
MC_AddWhiteText(menu, 72, 92+20/2-6, "Demos", false);
|
||||
b->common.height = 20/2+2;
|
||||
b->common.width = p->width;
|
||||
|
||||
menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, 54, 32);
|
||||
}
|
||||
|
||||
extern cvar_t team, skin;
|
||||
extern cvar_t topcolor;
|
||||
extern cvar_t bottomcolor;
|
||||
extern cvar_t skill;
|
||||
typedef struct {
|
||||
menuedit_t *nameedit;
|
||||
menuedit_t *teamedit;
|
||||
menuedit_t *skinedit;
|
||||
int topcolour;
|
||||
int lowercolour;
|
||||
} setupmenu_t;
|
||||
qboolean ApplySetupMenu (union menuoption_s *option,struct menu_s *menu, int key)
|
||||
{
|
||||
setupmenu_t *info = menu->data;
|
||||
if (key != K_ENTER)
|
||||
return false;
|
||||
Cvar_Set(&name, info->nameedit->text);
|
||||
Cvar_Set(&team, info->teamedit->text);
|
||||
Cvar_Set(&skin, info->skinedit->text);
|
||||
Cbuf_AddText(va("color %i %i\n", info->lowercolour, info->topcolour), RESTRICT_LOCAL);
|
||||
m_entersound=true;
|
||||
M_RemoveMenu(menu);
|
||||
return true;
|
||||
}
|
||||
qboolean SetupMenuColour (union menuoption_s *option,struct menu_s *menu, int key)
|
||||
{
|
||||
setupmenu_t *info = menu->data;
|
||||
if (*option->button.text == 'T')
|
||||
{
|
||||
if (key == K_ENTER || key == K_RIGHTARROW)
|
||||
{
|
||||
info->topcolour ++;
|
||||
if (info->topcolour>=14)
|
||||
info->topcolour=0;
|
||||
m_entersound=true;
|
||||
return true;
|
||||
}
|
||||
if (key == K_LEFTARROW)
|
||||
{
|
||||
info->topcolour --;
|
||||
if (info->topcolour<=0)
|
||||
info->topcolour=13;
|
||||
m_entersound=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key == K_ENTER || key == K_RIGHTARROW)
|
||||
{
|
||||
info->lowercolour ++;
|
||||
if (info->lowercolour>=14)
|
||||
info->lowercolour=0;
|
||||
m_entersound=true;
|
||||
return true;
|
||||
}
|
||||
if (key == K_LEFTARROW)
|
||||
{
|
||||
info->lowercolour --;
|
||||
if (info->lowercolour<=0)
|
||||
info->lowercolour=13;
|
||||
m_entersound=true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void MSetup_TransDraw (int x, int y, menucustom_t *option, menu_t *menu)
|
||||
{
|
||||
extern qbyte translationTable[256];
|
||||
setupmenu_t *info = menu->data;
|
||||
qpic_t *p;
|
||||
|
||||
p = Draw_CachePic ("gfx/bigbox.lmp");
|
||||
Draw_TransPic (x-12, y-8, p);
|
||||
p = Draw_SafeCachePic (va("gfx/player/%s.lmp", info->skinedit->text));
|
||||
if (!p) //fallback
|
||||
p = Draw_CachePic ("gfx/menuplyr.lmp");
|
||||
M_BuildTranslationTable(info->topcolour*16, info->lowercolour*16);
|
||||
Draw_TransPicTranslate (x, y, p, translationTable);
|
||||
}
|
||||
|
||||
void M_Menu_Setup_f (void)
|
||||
{
|
||||
setupmenu_t *info;
|
||||
menu_t *menu;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(sizeof(setupmenu_t));
|
||||
info = menu->data;
|
||||
|
||||
MC_AddPicture(menu, 16, 4, "gfx/qplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_multi.lmp");
|
||||
|
||||
|
||||
// MC_AddPicture(menu, 72, 32, Draw_CachePic ("gfx/mp_menu.lmp") );
|
||||
|
||||
menu->selecteditem = (menuoption_t*)
|
||||
(info->nameedit = MC_AddEdit(menu, 64, 40, "Your name", name.string));
|
||||
(info->teamedit = MC_AddEdit(menu, 64, 56, "Your team", team.string));
|
||||
(info->skinedit = MC_AddEdit(menu, 64, 72, "Your skin", skin.string));
|
||||
|
||||
MC_AddCustom(menu, 172, 88, NULL)->draw = MSetup_TransDraw;
|
||||
|
||||
MC_AddCommand(menu, 64, 96, "Top colour", SetupMenuColour);
|
||||
MC_AddCommand(menu, 64, 120, "Lower colour", SetupMenuColour);
|
||||
|
||||
MC_AddCommand(menu, 64, 152, "Accept changes", ApplySetupMenu);
|
||||
|
||||
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 32, NULL, false);
|
||||
|
||||
|
||||
info->lowercolour = bottomcolor.value;
|
||||
info->topcolour = topcolor.value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef CL_MASTER
|
||||
void M_Menu_ServerList_f (void)
|
||||
{
|
||||
key_dest = key_menu;
|
||||
m_state = m_slist;
|
||||
m_entersound = true;
|
||||
|
||||
MasterInfo_Begin();
|
||||
}
|
||||
#endif
|
||||
|
||||
void M_ServerList_Draw (void)
|
||||
{
|
||||
#ifdef CL_MASTER
|
||||
M_DrawServers();
|
||||
#endif
|
||||
}
|
||||
|
||||
void M_ServerList_Key (int k)
|
||||
{
|
||||
#ifdef CL_MASTER
|
||||
M_SListKey(k);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef CLIENTONLY
|
||||
void M_Menu_GameOptions_f (void)
|
||||
{
|
||||
}
|
||||
#else
|
||||
|
||||
typedef struct {
|
||||
menuedit_t *hostnameedit;
|
||||
menucombo_t *deathmatch;
|
||||
menucombo_t *numplayers;
|
||||
menucombo_t *teamplay;
|
||||
menucombo_t *skill;
|
||||
menucombo_t *timelimit;
|
||||
menucombo_t *fraglimit;
|
||||
menuedit_t *mapnameedit;
|
||||
menucheck_t *rundedicated;
|
||||
|
||||
int topcolour;
|
||||
int lowercolour;
|
||||
} newmultimenu_t;
|
||||
|
||||
static char *numplayeroptions[] = {
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"8",
|
||||
"12",
|
||||
"16",
|
||||
"20",
|
||||
"24",
|
||||
"32",
|
||||
NULL
|
||||
};
|
||||
|
||||
qboolean MultiBeginGame (union menuoption_s *option,struct menu_s *menu, int key)
|
||||
{
|
||||
newmultimenu_t *info = menu->data;
|
||||
if (key != K_ENTER)
|
||||
return false;
|
||||
|
||||
if (cls.state)
|
||||
Cbuf_AddText("disconnect\n", RESTRICT_LOCAL);
|
||||
|
||||
Cbuf_AddText(va("maxclients \"%s\"\n", numplayeroptions[info->numplayers->selectedoption]), RESTRICT_LOCAL);
|
||||
if (info->rundedicated->value)
|
||||
Cbuf_AddText("setrenderer dedicated\n", RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("hostname \"%s\"\n", info->hostnameedit->text), RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("deathmatch %i\n", info->deathmatch->selectedoption), RESTRICT_LOCAL);
|
||||
if (!info->deathmatch->selectedoption)
|
||||
Cbuf_AddText("coop 1\n", RESTRICT_LOCAL);
|
||||
else
|
||||
Cbuf_AddText("coop 0\n", RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("teamplay %i\n", info->teamplay->selectedoption), RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("skill %i\n", info->skill->selectedoption), RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("timelimit %i\n", info->timelimit->selectedoption*5), RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("fraglimit %i\n", info->fraglimit->selectedoption*10), RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("map \"%s\"\n", info->mapnameedit->text), RESTRICT_LOCAL);
|
||||
|
||||
if (info->rundedicated->value)
|
||||
{
|
||||
Cbuf_AddText("echo You can use the setrenderer command to return to a graphical interface at any time\n", RESTRICT_LOCAL);
|
||||
}
|
||||
|
||||
m_entersound=true;
|
||||
M_RemoveAllMenus();
|
||||
|
||||
return true;
|
||||
}
|
||||
void M_Menu_GameOptions_f (void)
|
||||
{
|
||||
extern cvar_t pr_maxedicts;
|
||||
static char *deathmatchoptions[] = {
|
||||
"Cooperative",
|
||||
"Deathmatch 1",
|
||||
"Deathmatch 2",
|
||||
"Deathmatch 3",
|
||||
"Deathmatch 4",
|
||||
"Deathmatch 5",
|
||||
NULL
|
||||
};
|
||||
static char *teamplayoptions[] = {
|
||||
"off",
|
||||
"friendly fire",
|
||||
"no friendly fire",
|
||||
NULL
|
||||
};
|
||||
static char *skilloptions[] = {
|
||||
"Easy",
|
||||
"Medium",
|
||||
"Hard",
|
||||
"NIGHTMARE",
|
||||
NULL
|
||||
};
|
||||
static char *timelimitoptions[] = {
|
||||
"no limit",
|
||||
"5 minutes",
|
||||
"10 minutes",
|
||||
"15 minutes",
|
||||
"20 minutes",
|
||||
"25 minutes",
|
||||
"30 minutes",
|
||||
"35 minutes",
|
||||
"40 minutes",
|
||||
"45 minutes",
|
||||
"50 minutes",
|
||||
"55 minutes",
|
||||
"1 hour",
|
||||
NULL
|
||||
};
|
||||
static char *fraglimitoptions[] = {
|
||||
"no limit",
|
||||
"10 frags",
|
||||
"20 frags",
|
||||
"30 frags",
|
||||
"40 frags",
|
||||
"50 frags",
|
||||
"60 frags",
|
||||
"70 frags",
|
||||
"80 frags",
|
||||
"90 frags",
|
||||
"100 frags",
|
||||
NULL
|
||||
};
|
||||
newmultimenu_t *info;
|
||||
menu_t *menu;
|
||||
int y = 40;
|
||||
int players;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(sizeof(newmultimenu_t));
|
||||
info = menu->data;
|
||||
|
||||
MC_AddPicture(menu, 16, 4, "gfx/qplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_multi.lmp");
|
||||
|
||||
|
||||
// MC_AddPicture(menu, 72, 32, ("gfx/mp_menu.lmp") );
|
||||
|
||||
menu->selecteditem = (menuoption_t*)
|
||||
MC_AddCommand (menu, 64, y, " Start game", MultiBeginGame);y+=16;
|
||||
|
||||
info->hostnameedit = MC_AddEdit (menu, 64, y, " Hostname", name.string);y+=16;
|
||||
|
||||
for (players = 0; players < sizeof(numplayeroptions)/ sizeof(numplayeroptions[0]); players++)
|
||||
{
|
||||
if (atoi(numplayeroptions[players]) >= maxclients.value)
|
||||
break;
|
||||
}
|
||||
|
||||
info->numplayers = MC_AddCombo (menu, 64, y, "Max players", (const char **)numplayeroptions, players);y+=8;
|
||||
|
||||
info->deathmatch = MC_AddCombo (menu, 64, y, " Deathmatch", (const char **)deathmatchoptions, deathmatch.value);y+=8;
|
||||
info->teamplay = MC_AddCombo (menu, 64, y, " Teamplay", (const char **)teamplayoptions, teamplay.value);y+=8;
|
||||
info->skill = MC_AddCombo (menu, 64, y, " Skill", (const char **)skilloptions, skill.value);y+=8;
|
||||
info->rundedicated = MC_AddCheckBox(menu, 64, y, " dedicated", NULL);y+=8;
|
||||
y+=8;
|
||||
info->timelimit = MC_AddCombo (menu, 64, y, " Time Limit", (const char **)timelimitoptions, timelimit.value/5);y+=8;
|
||||
info->fraglimit = MC_AddCombo (menu, 64, y, " Frag Limit", (const char **)fraglimitoptions, fraglimit.value/10);y+=8;
|
||||
y+=8;
|
||||
MC_AddSlider (menu, 64-7*8, y, "Extra edict support", &pr_maxedicts, 512, 2047);y+=8;
|
||||
y+=8;
|
||||
info->mapnameedit = MC_AddEdit (menu, 64, y, " map", "start");y+=16;
|
||||
info->mapnameedit = MC_AddEdit (menu, 64, y, " map", "start");y+=16;
|
||||
|
||||
|
||||
|
||||
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 32, NULL, false);
|
||||
|
||||
|
||||
info->lowercolour = bottomcolor.value;
|
||||
info->topcolour = topcolor.value;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,425 @@
|
|||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
|
||||
//these are awkward/strange
|
||||
qboolean M_Options_AlwaysRun (union menuoption_s *option, chk_set_t set)
|
||||
{
|
||||
if (set == CHK_CHECKED)
|
||||
return cl_forwardspeed.value > 200;
|
||||
else if (cl_forwardspeed.value > 200)
|
||||
{
|
||||
Cvar_SetValue (&cl_forwardspeed, 200);
|
||||
Cvar_SetValue (&cl_backspeed, 200);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cvar_SetValue (&cl_forwardspeed, 400);
|
||||
Cvar_SetValue (&cl_backspeed, 400);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
qboolean M_Options_InvertMouse (union menuoption_s *option, chk_set_t set)
|
||||
{
|
||||
if (set == CHK_CHECKED)
|
||||
return m_pitch.value < 0;
|
||||
else
|
||||
{
|
||||
Cvar_SetValue (&m_pitch, -m_pitch.value);
|
||||
return m_pitch.value < 0;
|
||||
}
|
||||
}
|
||||
|
||||
//options menu.
|
||||
void M_Menu_Options_f (void)
|
||||
{
|
||||
int q1, q2, h2;
|
||||
extern cvar_t cl_standardchat;
|
||||
#ifdef _WIN32
|
||||
extern qboolean vid_isfullscreen;
|
||||
#endif
|
||||
menu_t *menu;
|
||||
int y = 32;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(0);
|
||||
|
||||
q1 = COM_FDepthFile("gfx/menudot1.lmp", true);
|
||||
h2 = COM_FDepthFile("gfx/menu/menudot1.lmp", true);
|
||||
q2 = COM_FDepthFile("pics/m_cursor1.lmp", true);
|
||||
if (q2 < h2 && q2 < q1)
|
||||
{ //q2...
|
||||
}
|
||||
else if (h2 < q1)
|
||||
{ //h2
|
||||
MC_AddPicture(menu, 16, 0, "gfx/menu/hplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 0, "gfx/menu/title3.lmp");
|
||||
y+=32;
|
||||
}
|
||||
else
|
||||
{ //q1
|
||||
MC_AddPicture(menu, 16, 4, "gfx/qplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_option.lmp");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
menu->selecteditem = (union menuoption_s *)
|
||||
MC_AddConsoleCommand(menu, 16, y, " Customize controls", "menu_keys\n"); y+=8;
|
||||
MC_AddConsoleCommand(menu, 16, y, " Go to console", "toggleconsole\nplay misc/menu2.wav\n"); y+=8;
|
||||
MC_AddConsoleCommand(menu, 16, y, " Reset to defaults", "exec default.cfg\nplay misc/menu2.wav\n"); y+=8;
|
||||
|
||||
MC_AddSlider(menu, 16, y, " Mouse Speed", &sensitivity, 1, 10); y+=8;
|
||||
|
||||
MC_AddCheckBox(menu, 16, y, " Always Run", NULL)->func = M_Options_AlwaysRun; y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Invert Mouse", NULL)->func = M_Options_InvertMouse; y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Lookspring", &lookspring); y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Lookstrafe", &lookstrafe); y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Use old status bar", &cl_sbar); y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " HUD on left side", &cl_hudswap); y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Old-style chatting", &cl_standardchat);y+=8;
|
||||
y+=4;MC_AddEditCvar(menu, 16, y, " Imitate FPS", "cl_netfps"); y+=8+4;
|
||||
|
||||
MC_AddConsoleCommand(menu, 16, y, " Video Options", "menu_video\n"); y+=8;
|
||||
MC_AddConsoleCommand(menu, 16, y, " FPS Options", "menu_fps\n"); y+=8;
|
||||
MC_AddConsoleCommand(menu, 16, y, " Audio Options", "menu_audio\n"); y+=8;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!vid_isfullscreen)
|
||||
#endif
|
||||
{
|
||||
MC_AddCheckBox(menu, 16, y, " Use Mouse", &_windowed_mouse); y+=8;
|
||||
}
|
||||
|
||||
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 200, 32, NULL, false);
|
||||
}
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
typedef struct {
|
||||
int cursorpos;
|
||||
menuoption_t *cursoritem;
|
||||
|
||||
menutext_t *speaker[6];
|
||||
menutext_t *testsoundsource;
|
||||
|
||||
soundcardinfo_t *card;
|
||||
} audiomenuinfo_t;
|
||||
|
||||
qboolean M_Audio_Key (int key, struct menu_s *menu)
|
||||
{
|
||||
audiomenuinfo_t *info = menu->data;
|
||||
soundcardinfo_t *sc;
|
||||
for (sc = sndcardinfo; sc; sc = sc->next)
|
||||
{
|
||||
if (sc == info->card)
|
||||
break;
|
||||
}
|
||||
if (!sc)
|
||||
{
|
||||
M_RemoveMenu(menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (key == K_DOWNARROW)
|
||||
{
|
||||
info->testsoundsource->common.posy+=10;
|
||||
}
|
||||
if (key == K_UPARROW)
|
||||
{
|
||||
info->testsoundsource->common.posy-=10;
|
||||
}
|
||||
if (key == K_RIGHTARROW)
|
||||
{
|
||||
info->testsoundsource->common.posx+=10;
|
||||
}
|
||||
if (key == K_LEFTARROW)
|
||||
{
|
||||
info->testsoundsource->common.posx-=10;
|
||||
}
|
||||
|
||||
menu->selecteditem = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void M_Audio_StartSound (struct menu_s *menu)
|
||||
{
|
||||
int i;
|
||||
vec3_t org;
|
||||
audiomenuinfo_t *info = menu->data;
|
||||
soundcardinfo_t *sc;
|
||||
|
||||
static float lasttime;
|
||||
|
||||
for (sc = sndcardinfo; sc; sc = sc->next)
|
||||
{
|
||||
if (sc == info->card)
|
||||
break;
|
||||
}
|
||||
if (!sc)
|
||||
{
|
||||
M_RemoveMenu(menu);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->sn.numchannels; i++)
|
||||
{
|
||||
info->speaker[i]->common.posx = 320/2 - sin(sc->yaw[i]*M_PI/180) * 50;
|
||||
info->speaker[i]->common.posy = 200/2 - cos(sc->yaw[i]*M_PI/180) * 50;
|
||||
}
|
||||
|
||||
if (lasttime+0.5 < Sys_DoubleTime())
|
||||
{
|
||||
lasttime = Sys_DoubleTime();
|
||||
org[0] = listener_origin[0] + listener_right[0]*(info->testsoundsource->common.posx-320/2) + listener_forward[0]*(info->testsoundsource->common.posy-200/2);
|
||||
org[1] = listener_origin[1] + listener_right[1]*(info->testsoundsource->common.posx-320/2) + listener_forward[1]*(info->testsoundsource->common.posy-200/2);
|
||||
org[2] = listener_origin[2] + listener_right[2]*(info->testsoundsource->common.posx-320/2) + listener_forward[2]*(info->testsoundsource->common.posy-200/2);
|
||||
S_StartSound(-1, 0, S_PrecacheSound("misc/menu1.wav"), org, 1, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void M_Menu_Audio_Speakers_f (void)
|
||||
{
|
||||
int i;
|
||||
audiomenuinfo_t *info;
|
||||
menu_t *menu;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(sizeof(audiomenuinfo_t));
|
||||
info = menu->data;
|
||||
menu->key = M_Audio_Key;
|
||||
menu->event = M_Audio_StartSound;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
info->speaker[i] = MC_AddBufferedText(menu, 0, 0, va("%i", i), false, true);
|
||||
|
||||
info->testsoundsource = MC_AddBufferedText(menu, 0, 0, "X", false, true);
|
||||
|
||||
info->card = sndcardinfo;
|
||||
|
||||
|
||||
menu->selecteditem = NULL;
|
||||
}
|
||||
|
||||
menucombo_t *MC_AddCvarCombo(menu_t *menu, int x, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values);
|
||||
void M_Menu_Audio_f (void)
|
||||
{
|
||||
int y = 32;
|
||||
menu_t *menu;
|
||||
extern cvar_t nosound, precache, snd_leftisright, snd_khz, snd_eax, snd_speakers, ambient_level;
|
||||
|
||||
static const char *soundqualityoptions[] = {
|
||||
"11025 Hz",
|
||||
"22050 Hz",
|
||||
"44100 Hz",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *soundqualityvalues[] = {
|
||||
"11.025",
|
||||
"22.050",
|
||||
"44.100",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *speakeroptions[] = {
|
||||
"Mono",
|
||||
"Stereo",
|
||||
"Quad",
|
||||
"5.1 surround",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *speakervalues[] = {
|
||||
"1",
|
||||
"2",
|
||||
"4",
|
||||
"6",
|
||||
NULL
|
||||
};
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(0);
|
||||
|
||||
MC_AddPicture(menu, 16, 4, "gfx/qplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_option.lmp");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
menu->selecteditem = (union menuoption_s *)
|
||||
|
||||
|
||||
MC_AddSlider(menu, 16, y, " CD Music Volume", &bgmvolume, 0, 1);y+=8;
|
||||
MC_AddSlider(menu, 16, y, " Sound Volume", &volume, 0, 1);y+=8;
|
||||
MC_AddSlider(menu, 16, y, " Ambient Volume", &ambient_level, 0, 1);y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " no sound", &nosound);y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " precache", &precache);y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Low Quality Sound", &loadas8bit);y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Flip Sound", &snd_leftisright);y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Experimental EAX 2", &snd_eax);y+=8;
|
||||
MC_AddCvarCombo(menu, 16, y, " Speaker setup", &snd_speakers, speakeroptions, speakervalues);y+=8;
|
||||
MC_AddCvarCombo(menu, 16, y, " Sound speed", &snd_khz, soundqualityoptions, soundqualityvalues);y+=8;
|
||||
MC_AddConsoleCommand(menu, 16, y, " Restart sound", "snd_restart\n");y+=8;
|
||||
|
||||
|
||||
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 200, 32, NULL, false);
|
||||
}
|
||||
|
||||
#else
|
||||
void M_Menu_Audio_f (void)
|
||||
{
|
||||
Con_Printf("No sound in cygwin\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void M_Menu_Particles_f (void)
|
||||
{
|
||||
int y = 32;
|
||||
menu_t *menu;
|
||||
extern cvar_t r_bouncysparks, r_particles_in_explosion, r_part_rain, gl_part_torch, gl_part_flame, gl_part_trifansparks;
|
||||
|
||||
static const char *r_part_rain_options[] = {
|
||||
"off",
|
||||
"on",
|
||||
"bouncy",
|
||||
NULL
|
||||
};
|
||||
static const char *r_part_rain_values[] = {
|
||||
"off",
|
||||
"on",
|
||||
"bouncy",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *gl_part_effects_ops[] = {
|
||||
"models",
|
||||
"particles",
|
||||
"off",
|
||||
NULL
|
||||
};
|
||||
static const char *gl_part_effects_vals[] = {
|
||||
"0",
|
||||
"1",
|
||||
"-1",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(0);
|
||||
|
||||
MC_AddPicture(menu, 16, 4, "gfx/qplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_option.lmp");
|
||||
|
||||
|
||||
menu->selecteditem = (union menuoption_s *)
|
||||
|
||||
MC_AddCheckBox(menu, 16, y, " sparks bounce", &r_bouncysparks);y+=8;
|
||||
MC_AddSlider(menu, 16, y, " exp spark count", &r_particles_in_explosion, 16, 1024);y+=8;
|
||||
MC_AddCvarCombo(menu, 16, y, " rain effect", &r_part_rain, r_part_rain_options, r_part_rain_values);y+=8;
|
||||
|
||||
#ifdef RGLQUAKE
|
||||
if (qrenderer == QR_OPENGL) //sw doesn't have these.
|
||||
{
|
||||
MC_AddCvarCombo(menu, 16, y, " WallTorch effect", &gl_part_torch, gl_part_effects_ops, gl_part_effects_vals);y+=8;
|
||||
MC_AddCvarCombo(menu, 16, y, " Open flame effect", &gl_part_flame, gl_part_effects_ops, gl_part_effects_vals);y+=8;
|
||||
MC_AddCheckBox(menu, 16, y, " Trifan Sparks", &gl_part_trifansparks);y+=8;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 200, 32, NULL, false);
|
||||
}
|
||||
|
||||
|
||||
void M_Menu_FPS_f (void)
|
||||
{
|
||||
int y = 32;
|
||||
menu_t *menu;
|
||||
#ifdef RGLQUAKE
|
||||
extern cvar_t gl_compress, gl_waterripples, gl_detail, gl_bump, gl_2dscale, r_flashblend;
|
||||
#endif
|
||||
extern cvar_t r_stains, r_bloodstains, r_loadlits, d_smooth, d_mipscale, d_mipcap, r_dynamic, v_contentblend, show_fps;;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(0);
|
||||
|
||||
MC_AddPicture(menu, 16, 4, "gfx/qplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_option.lmp");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
menu->selecteditem = (union menuoption_s *)
|
||||
|
||||
MC_AddConsoleCommand(menu, 48, y, " Particle Options", "menu_particles\n"); y+=8;
|
||||
|
||||
MC_AddCheckBox(menu, 48, y, " Show FPS", &show_fps);y+=8;
|
||||
|
||||
MC_AddCheckBox(menu, 48, y, " Content blend", &v_contentblend);y+=8;
|
||||
MC_AddCheckBox(menu, 48, y, " Dynamic lights", &r_dynamic);y+=8;
|
||||
MC_AddCheckBox(menu, 48, y, " Stainmaps", &r_stains);y+=8;
|
||||
|
||||
switch(qrenderer)
|
||||
{
|
||||
#ifdef RGLQUAKE
|
||||
case QR_OPENGL:
|
||||
MC_AddCheckBox(menu, 48, y, " Blood stains", &r_bloodstains);y+=8;
|
||||
MC_AddCheckBox(menu, 48, y, " Load .lit files", &r_loadlits);y+=8;
|
||||
MC_AddCheckBox(menu, 48, y, " Flashblending", &r_flashblend);y+=8;
|
||||
MC_AddCheckBox(menu, 48, y, " Detailmaps", &gl_detail);y+=8;
|
||||
MC_AddCheckBox(menu, 48, y, " Bumpmaps", &gl_bump);y+=8;
|
||||
MC_AddCheckBox(menu, 48, y, " Tex Compression", &gl_compress);y+=8;
|
||||
MC_AddCheckBox(menu, 48, y, "Other Water Effect", &gl_waterripples);y+=8;
|
||||
MC_AddSlider(menu, 48, y, " 2D resolution", &gl_2dscale, 0, 1);y+=8;
|
||||
break;
|
||||
#endif
|
||||
#ifdef SWQUAKE
|
||||
case QR_SOFTWARE:
|
||||
if (r_pixbytes == 4)
|
||||
{MC_AddCheckBox(menu, 48, y, " Load .lit files", &r_loadlits);y+=8;}
|
||||
MC_AddCheckBox(menu, 48, y, " Texture Smoothing", &d_smooth);y+=8;
|
||||
MC_AddSlider(menu, 48, y, " Mipmap scale", &d_mipscale, 0.1, 3);y+=8;
|
||||
MC_AddSlider(menu, 48, y, " Mipmap Capping", &d_mipcap, 0, 3);y+=8;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// MC_AddCheckBox(menu, 48, y, "32 bit texture loading", &r_32bit);y+=8; ADD ME
|
||||
|
||||
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 200, 32, NULL, false);
|
||||
}
|
||||
|
||||
void M_OptionsMenusInit(void)
|
||||
{
|
||||
Cmd_AddCommand ("menu_options", M_Menu_Options_f);
|
||||
Cmd_AddCommand ("menu_video", M_Menu_Video_f);
|
||||
Cmd_AddCommand ("menu_audio", M_Menu_Audio_f);
|
||||
Cmd_AddCommand ("menu_fps", M_Menu_FPS_f);
|
||||
Cmd_AddCommand ("menu_particles", M_Menu_Particles_f);
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
int selectitem;
|
||||
menu_t *menu_script;
|
||||
cvar_t menualias = {"menualias", ""};
|
||||
|
||||
void M_Script_Remove (menu_t *menu)
|
||||
{
|
||||
menu_script = NULL;
|
||||
Cvar_Set(&menualias, "");
|
||||
}
|
||||
qboolean M_Script_Key (int key, menu_t *menu)
|
||||
{
|
||||
if (menu->selecteditem && menu->selecteditem->common.type == mt_edit)
|
||||
return false;
|
||||
if (key >= '0' && key <= '9')
|
||||
{
|
||||
if (key == '0') //specal case so that "hello" < "0"... (plus matches impulses)
|
||||
Cbuf_AddText(va("set option 10\n%s\n", menualias.string), RESTRICT_LOCAL);
|
||||
else
|
||||
Cbuf_AddText(va("set option %c\n%s\n", key, menualias.string), RESTRICT_LOCAL);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void M_Menu_Clear_f (void)
|
||||
{
|
||||
if (menu_script)
|
||||
{
|
||||
M_RemoveMenu(menu_script);
|
||||
menu_script = NULL;
|
||||
}
|
||||
|
||||
// Cvar_Set(menualias.name, "");
|
||||
}
|
||||
|
||||
void M_Menu_Script_f (void) //create a menu.
|
||||
{
|
||||
int items;
|
||||
extern menu_t *currentmenu;
|
||||
menu_t *oldmenu;
|
||||
char *alias = Cmd_Argv(1);
|
||||
// if (key_dest != key_console)
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
if (menu_script != currentmenu)
|
||||
m_entersound = true;
|
||||
|
||||
selectitem = 0;
|
||||
items=0;
|
||||
|
||||
if (menu_script)
|
||||
{
|
||||
menuoption_t *option;
|
||||
for (option = menu_script->options; option; option = option->common.next)
|
||||
{
|
||||
if (option->common.type == mt_button)
|
||||
{
|
||||
if (menu_script->selecteditem == option)
|
||||
selectitem = items;
|
||||
items++;
|
||||
}
|
||||
}
|
||||
selectitem = items - selectitem-1;
|
||||
M_Menu_Clear_f();
|
||||
}
|
||||
|
||||
oldmenu = currentmenu;
|
||||
|
||||
menu_script = M_CreateMenu(0);
|
||||
if (oldmenu)
|
||||
{
|
||||
M_HideMenu(oldmenu); //bring to front
|
||||
M_AddMenu(oldmenu);
|
||||
}
|
||||
menu_script->remove = M_Script_Remove;
|
||||
menu_script->key = M_Script_Key;
|
||||
|
||||
if (Cmd_Argc() == 1 || !*alias)
|
||||
Cvar_Set(&menualias, "_");
|
||||
else
|
||||
Cvar_Set(&menualias, alias);
|
||||
}
|
||||
|
||||
void M_Menu_Box_f (void)
|
||||
{
|
||||
int x = atoi(Cmd_Argv(1));
|
||||
int y = atoi(Cmd_Argv(2));
|
||||
int width = atoi(Cmd_Argv(3));
|
||||
int height = atoi(Cmd_Argv(4));
|
||||
|
||||
if (!menu_script)
|
||||
{
|
||||
Con_Printf("%s with no active menu\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
|
||||
MC_AddBox(menu_script, x, y, width/8, height/8);
|
||||
}
|
||||
|
||||
void M_Menu_CheckBox_f (void)
|
||||
{
|
||||
int x = atoi(Cmd_Argv(1));
|
||||
int y = atoi(Cmd_Argv(2));
|
||||
char *text = Cmd_Argv(3);
|
||||
char *cvarname = Cmd_Argv(4);
|
||||
cvar_t *cvar;
|
||||
|
||||
if (!menu_script)
|
||||
{
|
||||
Con_Printf("%s with no active menu\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
cvar = Cvar_Get(cvarname, text, 0, "User variables");
|
||||
if (!cvar)
|
||||
return;
|
||||
MC_AddCheckBox(menu_script, x, y, text, cvar);
|
||||
}
|
||||
|
||||
void M_Menu_Slider_f (void)
|
||||
{
|
||||
int x = atoi(Cmd_Argv(1));
|
||||
int y = atoi(Cmd_Argv(2));
|
||||
char *text = Cmd_Argv(3);
|
||||
char *cvarname = Cmd_Argv(4);
|
||||
float min = atof(Cmd_Argv(5));
|
||||
float max = atof(Cmd_Argv(6));
|
||||
cvar_t *cvar;
|
||||
|
||||
if (!menu_script)
|
||||
{
|
||||
Con_Printf("%s with no active menu\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
cvar = Cvar_Get(cvarname, text, 0, "User variables");
|
||||
if (!cvar)
|
||||
return;
|
||||
MC_AddSlider(menu_script, x, y, text, cvar, min, max);
|
||||
}
|
||||
|
||||
void M_Menu_Picture_f (void)
|
||||
{
|
||||
int x = atoi(Cmd_Argv(1));
|
||||
int y = atoi(Cmd_Argv(2));
|
||||
char *picname = Cmd_Argv(3);
|
||||
|
||||
if (!menu_script)
|
||||
{
|
||||
Con_Printf("%s with no active menu\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
|
||||
MC_AddPicture(menu_script, x, y, picname);
|
||||
}
|
||||
|
||||
void M_Menu_Edit_f (void)
|
||||
{
|
||||
int x = atoi(Cmd_Argv(1));
|
||||
int y = atoi(Cmd_Argv(2));
|
||||
char *text = Cmd_Argv(3);
|
||||
char *def = Cmd_Argv(4);
|
||||
|
||||
if (!menu_script)
|
||||
{
|
||||
Con_Printf("%s with no active menu\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
|
||||
MC_AddEditCvar(menu_script, x, y, text, def);
|
||||
}
|
||||
|
||||
void M_Menu_Text_f (void)
|
||||
{
|
||||
menuoption_t *option;
|
||||
int x = atoi(Cmd_Argv(1));
|
||||
int y = atoi(Cmd_Argv(2));
|
||||
char *text = Cmd_Argv(3);
|
||||
char *command = Cmd_Argv(4);
|
||||
|
||||
if (!menu_script)
|
||||
{
|
||||
Con_Printf("%s with no active menu\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
if (Cmd_Argc() == 4)
|
||||
MC_AddBufferedText(menu_script, x, y, text, false, false);
|
||||
else
|
||||
{
|
||||
option = (menuoption_t *)MC_AddConsoleCommand(menu_script, x, y, text, va("set option %s\n%s\n", command, menualias.string));
|
||||
if (selectitem-- == 0)
|
||||
menu_script->selecteditem = option;
|
||||
}
|
||||
}
|
||||
/*
|
||||
menuclear
|
||||
menualias menucallback
|
||||
|
||||
menubox 0 0 320 8
|
||||
menutext 0 0 "GO GO GO!!!" "radio21"
|
||||
menutext 0 8 "Fall back" "radio22"
|
||||
menutext 0 8 "Stick together" "radio23"
|
||||
menutext 0 16 "Get in position" "radio24"
|
||||
menutext 0 24 "Storm the front" "radio25"
|
||||
menutext 0 24 "Report in" "radio26"
|
||||
menutext 0 24 "Cancel"
|
||||
*/
|
||||
void M_Script_Init(void)
|
||||
{
|
||||
Cmd_AddCommand("menuclear", M_Menu_Clear_f);
|
||||
Cmd_AddCommand("conmenu", M_Menu_Script_f);
|
||||
Cmd_AddCommand("menubox", M_Menu_Box_f);
|
||||
Cmd_AddCommand("menuedit", M_Menu_Edit_f);
|
||||
Cmd_AddCommand("menutext", M_Menu_Text_f);
|
||||
Cmd_AddCommand("menupic", M_Menu_Picture_f);
|
||||
Cmd_AddCommand("menucheck", M_Menu_CheckBox_f);
|
||||
Cmd_AddCommand("menuslider", M_Menu_Slider_f);
|
||||
|
||||
Cvar_Register(&menualias, "Scripting");
|
||||
}
|
|
@ -0,0 +1,483 @@
|
|||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
#ifndef CLIENTONLY
|
||||
//=============================================================================
|
||||
/* LOAD/SAVE MENU */
|
||||
|
||||
#define FTESAVEGAME_VERSION 25000
|
||||
|
||||
typedef struct {
|
||||
int issave;
|
||||
int cursorpos;
|
||||
menutext_t *cursoritem;
|
||||
} loadsavemenuinfo_t;
|
||||
|
||||
#define MAX_SAVEGAMES 20
|
||||
char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
|
||||
int loadable[MAX_SAVEGAMES];
|
||||
|
||||
menubutton_t *VARGS MC_AddConsoleCommandf(menu_t *menu, int x, int y, char *text, char *command, ...);
|
||||
|
||||
void M_ScanSaves (void)
|
||||
{
|
||||
int i, j;
|
||||
char name[MAX_OSPATH];
|
||||
FILE *f;
|
||||
int version;
|
||||
|
||||
for (i=0 ; i<MAX_SAVEGAMES ; i++)
|
||||
{
|
||||
strcpy (m_filenames[i], "--- UNUSED SLOT ---");
|
||||
loadable[i] = false;
|
||||
|
||||
sprintf (name, "%s/s%i/info.fsv", com_gamedir, i);
|
||||
f = fopen (name, "rb");
|
||||
if (f)
|
||||
{
|
||||
fscanf (f, "%i\n", &version);
|
||||
if (version != FTESAVEGAME_VERSION)
|
||||
{
|
||||
Q_strncpyz (m_filenames[i], "Incompatable version", sizeof(m_filenames[i]));
|
||||
fclose (f);
|
||||
continue;
|
||||
}
|
||||
|
||||
fscanf (f, "%79s\n", name);
|
||||
Q_strncpyz (m_filenames[i], name, sizeof(m_filenames[i]));
|
||||
|
||||
|
||||
// change _ back to space
|
||||
for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
|
||||
if (m_filenames[i][j] == '_')
|
||||
m_filenames[i][j] = ' ';
|
||||
loadable[i] = true;
|
||||
fclose (f);
|
||||
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
sprintf (name, "%s/s%i.sav", com_gamedir, i);
|
||||
f = fopen (name, "rb");
|
||||
if (!f)
|
||||
continue;
|
||||
fscanf (f, "%i\n", &version);
|
||||
if (version != SAVEGAME_VERSION && version != 5 && version != 6)
|
||||
{
|
||||
Q_strncpyz (m_filenames[i], "Incompatable version", sizeof(m_filenames[i]));
|
||||
fclose (f);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fscanf (f, "%79s\n", name);
|
||||
Q_strncpyz (m_filenames[i], name, sizeof(m_filenames[i]));
|
||||
}
|
||||
|
||||
// change _ back to space
|
||||
for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
|
||||
if (m_filenames[i][j] == '_')
|
||||
m_filenames[i][j] = ' ';
|
||||
loadable[i] = true;
|
||||
fclose (f);*/
|
||||
}
|
||||
}
|
||||
|
||||
void M_Menu_Save_f (void)
|
||||
{
|
||||
menuoption_t *op = NULL;
|
||||
menu_t *menu;
|
||||
int i;
|
||||
|
||||
if (!sv.state)
|
||||
return;
|
||||
|
||||
if (cl.intermission)
|
||||
return;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(sizeof(loadsavemenuinfo_t));
|
||||
menu->data = menu+1;
|
||||
|
||||
MC_AddCenterPicture (menu, 4, "gfx/p_save.lmp");
|
||||
menu->cursoritem = (menuoption_t *)MC_AddRedText(menu, 8, 32, NULL, false);
|
||||
|
||||
M_ScanSaves ();
|
||||
|
||||
for (i=0 ; i< MAX_SAVEGAMES; i++)
|
||||
{
|
||||
op = (menuoption_t *)MC_AddConsoleCommandf(menu, 16, 32+8*i, m_filenames[i], "savegame s%i\ntogglemenu\n", i);
|
||||
if (!menu->selecteditem)
|
||||
menu->selecteditem = op;
|
||||
}
|
||||
}
|
||||
void M_Menu_Load_f (void)
|
||||
{
|
||||
menuoption_t *op = NULL;
|
||||
menu_t *menu;
|
||||
int i;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(sizeof(loadsavemenuinfo_t));
|
||||
menu->data = menu+1;
|
||||
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_load.lmp");
|
||||
menu->cursoritem = (menuoption_t *)MC_AddRedText(menu, 8, 32, NULL, false);
|
||||
|
||||
M_ScanSaves ();
|
||||
|
||||
for (i=0 ; i< MAX_SAVEGAMES; i++)
|
||||
{
|
||||
if (loadable[i])
|
||||
op = (menuoption_t *)MC_AddConsoleCommandf(menu, 16, 32+8*i, m_filenames[i], "loadgame s%i\ntogglemenu\n", i);
|
||||
else
|
||||
MC_AddWhiteText(menu, 16, 32+8*i, m_filenames[i], false);
|
||||
if (!menu->selecteditem && op)
|
||||
menu->selecteditem = op;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void M_Menu_SinglePlayer_f (void)
|
||||
{
|
||||
int q1, q2, h2;
|
||||
menubutton_t *b;
|
||||
menu_t *menu;
|
||||
qpic_t *p;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
q1 = COM_FDepthFile("gfx/sp_menu.lmp", true);
|
||||
h2 = COM_FDepthFile("gfx/menu/title2.lmp", true);
|
||||
q2 = COM_FDepthFile("pics/m_banner_game.pcx", true);
|
||||
if (q2 < h2 && q2 < q1)
|
||||
{ //q2...
|
||||
menu = M_CreateMenu(0);
|
||||
|
||||
MC_AddCenterPicture(menu, 4, "m_banner_game");
|
||||
|
||||
menu->selecteditem = (menuoption_t*)
|
||||
MC_AddConsoleCommand (menu, 64, 40, "Easy", "skill 0;deathmatch 0; coop 0;newgame\n");
|
||||
MC_AddConsoleCommand (menu, 64, 48, "Medium", "skill 1;deathmatch 0; coop 0;newgame\n");
|
||||
MC_AddConsoleCommand (menu, 64, 56, "Hard", "skill 2;deathmatch 0; coop 0;newgame\n");
|
||||
|
||||
MC_AddConsoleCommand (menu, 64, 72, "Load Game", "menu_load\n");
|
||||
MC_AddConsoleCommand (menu, 64, 80, "Save Game", "menu_save\n");
|
||||
return;
|
||||
}
|
||||
else if (h2 < q1)
|
||||
{ //h2
|
||||
menu = M_CreateMenu(0);
|
||||
MC_AddPicture(menu, 16, 0, "gfx/menu/hplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 0, "gfx/menu/title1.lmp");
|
||||
|
||||
menu->selecteditem = (menuoption_t*)
|
||||
MC_AddConsoleCommand (menu, 64, 64, "Easy", "togglemenu\nskill 0;deathmatch 0; coop 0;map demo1\n");
|
||||
MC_AddConsoleCommand (menu, 64, 72, "Medium", "togglemenu\nskill 1;deathmatch 0; coop 0;map demo1\n");
|
||||
MC_AddConsoleCommand (menu, 64, 80, "Hard", "togglemenu\nskill 2;deathmatch 0; coop 0;map demo1\n");
|
||||
|
||||
// MC_AddConsoleCommand (menu, 64, 96, "Load Game", "menu_load\n");
|
||||
MC_AddConsoleCommand (menu, 64, 104, "Save Game", "menu_save\n");
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{ //q1
|
||||
menu = M_CreateMenu(0);
|
||||
MC_AddPicture(menu, 16, 4, "gfx/qplaque.lmp");
|
||||
MC_AddCenterPicture(menu, 4, "gfx/p_option.lmp");
|
||||
}
|
||||
|
||||
p = Draw_CachePic("gfx/sp_menu.lmp");
|
||||
if (!p)
|
||||
{
|
||||
MC_AddBox (menu, 60, 10*8, 23, 4);
|
||||
|
||||
MC_AddWhiteText(menu, 92, 12*8, "Could find file", false);
|
||||
MC_AddWhiteText(menu, 92, 13*8, "gfx/sp_menu.lmp", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CLIENTONLY
|
||||
MC_AddBox (menu, 60, 10*8, 23, 4);
|
||||
|
||||
MC_AddWhiteText(menu, 92, 12*8, "QuakeWorld is for", false);
|
||||
MC_AddWhiteText(menu, 92, 13*8, "Internet play only", false);
|
||||
#else
|
||||
MC_AddPicture(menu, 72, 32, "gfx/sp_menu.lmp");
|
||||
|
||||
b = MC_AddConsoleCommand (menu, 16, 32, "", "togglemenu\nmaxclients 1;deathmatch 0;coop 0;map start\n");
|
||||
menu->selecteditem = (menuoption_t *)b;
|
||||
b->common.width = p->width;
|
||||
b->common.height = 20;
|
||||
b = MC_AddConsoleCommand (menu, 16, 52, "", "menu_load\n");
|
||||
b->common.width = p->width;
|
||||
b->common.height = 20;
|
||||
b = MC_AddConsoleCommand (menu, 16, 72, "", "menu_save\n");
|
||||
b->common.width = p->width;
|
||||
b->common.height = 20;
|
||||
|
||||
menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, 54, 32);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
menucustom_t *list;
|
||||
int nummatches;
|
||||
int selected;
|
||||
int firstshown;
|
||||
int maxmatches;
|
||||
int pathlen;
|
||||
|
||||
char *command[64]; //these let the menu be used for nearly any sort of file browser.
|
||||
char *ext[64];
|
||||
int numext;
|
||||
|
||||
struct demofilelist_s{
|
||||
char name[64];
|
||||
int size;
|
||||
} *options;
|
||||
} demomenu_t;
|
||||
|
||||
void M_DemoDraw(int x, int y, menucustom_t *control, menu_t *menu)
|
||||
{
|
||||
char *text;
|
||||
int i;
|
||||
demomenu_t *info = menu->data;
|
||||
|
||||
if (info->firstshown > info->selected)
|
||||
info->firstshown = info->selected;
|
||||
if ((vid.height - y)/8 < info->selected - info->firstshown+2)
|
||||
info->firstshown = info->selected - (vid.height - y)/8+2;
|
||||
|
||||
i = info->firstshown;
|
||||
while(i < info->nummatches)
|
||||
{
|
||||
if (info->options[i].size)
|
||||
text = va("%-30s %6iKB", info->options[i].name+info->pathlen, info->options[i].size/1024);
|
||||
else
|
||||
text = info->options[i].name+info->pathlen;
|
||||
if (i == info->selected)
|
||||
Draw_Alt_String(x+8, y+8, text);
|
||||
else
|
||||
Draw_String(x+8, y+8, text);
|
||||
y+=8;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
void ShowDemoMenu (menu_t *menu, char *path);
|
||||
qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key)
|
||||
{
|
||||
demomenu_t *info = menu->data;
|
||||
if (!info->nummatches)
|
||||
return false;
|
||||
switch (key)
|
||||
{
|
||||
case K_UPARROW:
|
||||
info->selected--;
|
||||
if (info->selected < 0)
|
||||
info->selected = 0;
|
||||
return true;
|
||||
case K_DOWNARROW:
|
||||
info->selected++;
|
||||
if (info->selected > info->nummatches-1)
|
||||
info->selected = info->nummatches-1;
|
||||
return true;
|
||||
case K_PGUP:
|
||||
info->selected-=10;
|
||||
if (info->selected < 0)
|
||||
info->selected = 0;
|
||||
return true;
|
||||
case K_PGDN:
|
||||
info->selected+=10;
|
||||
if (info->selected > info->nummatches-1)
|
||||
info->selected = info->nummatches-1;
|
||||
return true;
|
||||
case K_ENTER:
|
||||
if (info->options[info->selected].name[strlen(info->options[info->selected].name)-1] == '/') //last char is a slash
|
||||
ShowDemoMenu(menu, va("%s", info->options[info->selected].name));
|
||||
else
|
||||
{
|
||||
int extnum;
|
||||
for (extnum = 0; extnum < info->numext; extnum++)
|
||||
if (!stricmp(info->options[info->selected].name + strlen(info->options[info->selected].name)-4, info->ext[extnum]))
|
||||
break;
|
||||
|
||||
if (extnum == info->numext) //wasn't on our list of extensions.
|
||||
extnum = 0;
|
||||
|
||||
Cbuf_AddText(va("%s %s\n", info->command[extnum], info->options[info->selected].name), RESTRICT_LOCAL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int DemoAddItem(char *filename, int size, void *parm)
|
||||
{
|
||||
int match;
|
||||
int extnum;
|
||||
demomenu_t *menu = parm;
|
||||
if (filename[strlen(filename)-1] != '/')
|
||||
{
|
||||
for (extnum = 0; extnum < menu->numext; extnum++)
|
||||
if (!stricmp(filename + strlen(filename)-4, menu->ext[extnum]))
|
||||
break;
|
||||
|
||||
if (extnum == menu->numext) //wasn't on our list of extensions.
|
||||
return true;
|
||||
}
|
||||
if (menu->maxmatches < menu->nummatches+10)
|
||||
{
|
||||
menu->maxmatches = menu->nummatches+10;
|
||||
menu->options = BZ_Realloc(menu->options, menu->maxmatches*sizeof(struct demofilelist_s));
|
||||
}
|
||||
for (match = 0; match < menu->nummatches; match++)
|
||||
if (!strcmp(menu->options[match].name, filename))
|
||||
return true;
|
||||
Q_strncpyz(menu->options[menu->nummatches].name, filename, sizeof(menu->options[menu->nummatches].name));
|
||||
menu->options[menu->nummatches].size = size;
|
||||
menu->nummatches++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void M_Demo_Remove (menu_t *menu)
|
||||
{
|
||||
demomenu_t *info = menu->data;
|
||||
if (info->options)
|
||||
BZ_Free(info->options);
|
||||
}
|
||||
|
||||
void ShowDemoMenu (menu_t *menu, char *path)
|
||||
{
|
||||
int c;
|
||||
char *s;
|
||||
char match[256];
|
||||
while (!strcmp(path+strlen(path)-3, "../"))
|
||||
{
|
||||
c = 0;
|
||||
for (s = path+strlen(path)-3; s >= path; s--)
|
||||
{
|
||||
if (*s == '/')
|
||||
{
|
||||
c++;
|
||||
s[1] = '\0';
|
||||
if (c == 2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c<2)
|
||||
*path = '\0';
|
||||
}
|
||||
((demomenu_t*)menu->data)->nummatches = 0;
|
||||
((demomenu_t*)menu->data)->firstshown = 0;
|
||||
((demomenu_t*)menu->data)->selected = 0;
|
||||
((demomenu_t*)menu->data)->pathlen = strlen(path);
|
||||
|
||||
if (*path)
|
||||
{
|
||||
sprintf(match, "%s../", path);
|
||||
DemoAddItem(match, 0, menu->data);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
sprintf(match, "%s*.*", path);
|
||||
#else
|
||||
sprintf(match, "%s*", path);
|
||||
#endif
|
||||
COM_EnumerateFiles(match, DemoAddItem, menu->data);
|
||||
}
|
||||
|
||||
void M_Menu_Demos_f (void)
|
||||
{
|
||||
demomenu_t *info;
|
||||
menu_t *menu;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(sizeof(demomenu_t));
|
||||
menu->remove = M_Demo_Remove;
|
||||
info = menu->data;
|
||||
|
||||
info->command[0] = "playdemo";
|
||||
info->ext[0] = ".qwd";
|
||||
info->command[1] = "playdemo";
|
||||
info->ext[1] = ".dem";
|
||||
info->command[2] = "playdemo";
|
||||
info->ext[2] = ".dm2";
|
||||
info->command[3] = "mvdplay";
|
||||
info->ext[3] = ".mvd";
|
||||
//there are also quizmo demos (.qwz) out there...
|
||||
//we don't support them, but if we were to ask quizmo to decode them for us, we could do.
|
||||
info->numext = 3;
|
||||
|
||||
MC_AddWhiteText(menu, 24, 8, "Demos", false);
|
||||
MC_AddWhiteText(menu, 16, 24, "\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37", false);
|
||||
|
||||
info->list = MC_AddCustom(menu, 0, 32, NULL);
|
||||
info->list->draw = M_DemoDraw;
|
||||
info->list->key = M_DemoKey;
|
||||
|
||||
menu->selecteditem = (menuoption_t*)info->list;
|
||||
|
||||
ShowDemoMenu(menu, "");
|
||||
}
|
||||
|
||||
void M_Menu_MediaFiles_f (void)
|
||||
{
|
||||
demomenu_t *info;
|
||||
menu_t *menu;
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
menu = M_CreateMenu(sizeof(demomenu_t));
|
||||
menu->remove = M_Demo_Remove;
|
||||
info = menu->data;
|
||||
|
||||
info->ext[0] = ".m3u";
|
||||
info->command[0] = "mediaplaylist";
|
||||
info->ext[1] = ".mp3";
|
||||
info->command[1] = "mediaadd";
|
||||
info->ext[2] = ".wav";
|
||||
info->command[2] = "mediaadd";
|
||||
info->ext[3] = ".ogg"; //will this ever be added properly?
|
||||
info->command[3] = "mediaadd";
|
||||
info->ext[4] = ".roq";
|
||||
info->command[4] = "playfilm";
|
||||
info->numext = 5;
|
||||
|
||||
#ifdef _WIN32 //avis are only playable on windows due to a windows dll being used to decode them.
|
||||
info->ext[info->numext] = ".avi";
|
||||
info->command[info->numext] = "playfilm";
|
||||
info->numext++;
|
||||
#endif
|
||||
|
||||
MC_AddWhiteText(menu, 24, 8, "Media List", false);
|
||||
MC_AddWhiteText(menu, 16, 24, "\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37", false);
|
||||
|
||||
info->list = MC_AddCustom(menu, 0, 32, NULL);
|
||||
info->list->draw = M_DemoDraw;
|
||||
info->list->key = M_DemoKey;
|
||||
|
||||
menu->selecteditem = (menuoption_t*)info->list;
|
||||
|
||||
ShowDemoMenu(menu, "");
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,971 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
|
||||
void M_Menu_Audio_f (void);
|
||||
void M_Menu_Demos_f (void);
|
||||
|
||||
m_state_t m_state;
|
||||
|
||||
extern menu_t *menu_script;
|
||||
|
||||
qboolean m_entersound; // play after drawing a frame, so caching
|
||||
// won't disrupt the sound
|
||||
qboolean m_recursiveDraw;
|
||||
|
||||
int m_return_state;
|
||||
qboolean m_return_onerror;
|
||||
char m_return_reason [32];
|
||||
|
||||
#define StartingGame (m_multiplayer_cursor == 1)
|
||||
#define JoiningGame (m_multiplayer_cursor == 0)
|
||||
#define SerialConfig (m_net_cursor == 0)
|
||||
#define DirectConfig (m_net_cursor == 1)
|
||||
#define IPXConfig (m_net_cursor == 2)
|
||||
#define TCPIPConfig (m_net_cursor == 3)
|
||||
|
||||
void M_ConfigureNetSubsystem(void);
|
||||
|
||||
cvar_t m_helpismedia = {"m_helpismedia", "0"};
|
||||
|
||||
//=============================================================================
|
||||
/* Support Routines */
|
||||
|
||||
/*
|
||||
================
|
||||
M_DrawCharacter
|
||||
|
||||
Draws one solid graphics character
|
||||
================
|
||||
*/
|
||||
void M_DrawCharacter (int cx, int line, unsigned int num)
|
||||
{
|
||||
Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
|
||||
}
|
||||
|
||||
void M_DrawColouredCharacter (int cx, int line, unsigned int num)
|
||||
{
|
||||
Draw_ColouredCharacter( cx + ((vid.width - 320)>>1), line, num);
|
||||
}
|
||||
void M_Print (int cx, int cy, qbyte *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
M_DrawCharacter (cx, cy, (*str)+128);
|
||||
str++;
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
void M_PrintColoured (int cx, int cy, int colour, qbyte *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
M_DrawColouredCharacter (cx, cy, (*str) + (colour<<8));
|
||||
str++;
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
void M_PrintWhite (int cx, int cy, qbyte *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
M_DrawCharacter (cx, cy, *str);
|
||||
str++;
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
void M_DrawTransPic (int x, int y, qpic_t *pic)
|
||||
{
|
||||
Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
|
||||
}
|
||||
|
||||
void M_DrawPic (int x, int y, qpic_t *pic)
|
||||
{
|
||||
Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
|
||||
}
|
||||
|
||||
qbyte identityTable[256];
|
||||
qbyte translationTable[256];
|
||||
|
||||
void M_BuildTranslationTable(int top, int bottom)
|
||||
{
|
||||
int j;
|
||||
qbyte *dest, *source;
|
||||
|
||||
for (j = 0; j < 256; j++)
|
||||
identityTable[j] = j;
|
||||
dest = translationTable;
|
||||
source = identityTable;
|
||||
memcpy (dest, source, 256);
|
||||
|
||||
if (top < 128) // the artists made some backwards ranges. sigh.
|
||||
memcpy (dest + TOP_RANGE, source + top, 16);
|
||||
else
|
||||
for (j=0 ; j<16 ; j++)
|
||||
dest[TOP_RANGE+j] = source[top+15-j];
|
||||
|
||||
if (bottom < 128)
|
||||
memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
|
||||
else
|
||||
for (j=0 ; j<16 ; j++)
|
||||
dest[BOTTOM_RANGE+j] = source[bottom+15-j];
|
||||
}
|
||||
|
||||
|
||||
void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
|
||||
{
|
||||
Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
|
||||
}
|
||||
|
||||
|
||||
void M_DrawTextBox (int x, int y, int width, int lines)
|
||||
{
|
||||
qpic_t *p;
|
||||
int cx, cy;
|
||||
int n;
|
||||
|
||||
// draw left side
|
||||
cx = x;
|
||||
cy = y;
|
||||
p = Draw_CachePic ("gfx/box_tl.lmp");
|
||||
M_DrawTransPic (cx, cy, p);
|
||||
p = Draw_CachePic ("gfx/box_ml.lmp");
|
||||
for (n = 0; n < lines; n++)
|
||||
{
|
||||
cy += 8;
|
||||
M_DrawTransPic (cx, cy, p);
|
||||
}
|
||||
p = Draw_CachePic ("gfx/box_bl.lmp");
|
||||
M_DrawTransPic (cx, cy+8, p);
|
||||
|
||||
// draw middle
|
||||
cx += 8;
|
||||
while (width > 0)
|
||||
{
|
||||
cy = y;
|
||||
p = Draw_CachePic ("gfx/box_tm.lmp");
|
||||
M_DrawTransPic (cx, cy, p);
|
||||
p = Draw_CachePic ("gfx/box_mm.lmp");
|
||||
for (n = 0; n < lines; n++)
|
||||
{
|
||||
cy += 8;
|
||||
if (n == 1)
|
||||
p = Draw_CachePic ("gfx/box_mm2.lmp");
|
||||
M_DrawTransPic (cx, cy, p);
|
||||
}
|
||||
p = Draw_CachePic ("gfx/box_bm.lmp");
|
||||
M_DrawTransPic (cx, cy+8, p);
|
||||
width -= 2;
|
||||
cx += 16;
|
||||
}
|
||||
|
||||
// draw right side
|
||||
cy = y;
|
||||
p = Draw_CachePic ("gfx/box_tr.lmp");
|
||||
M_DrawTransPic (cx, cy, p);
|
||||
p = Draw_CachePic ("gfx/box_mr.lmp");
|
||||
for (n = 0; n < lines; n++)
|
||||
{
|
||||
cy += 8;
|
||||
M_DrawTransPic (cx, cy, p);
|
||||
}
|
||||
p = Draw_CachePic ("gfx/box_br.lmp");
|
||||
M_DrawTransPic (cx, cy+8, p);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int m_save_demonum;
|
||||
|
||||
/*
|
||||
================
|
||||
M_ToggleMenu_f
|
||||
================
|
||||
*/
|
||||
void M_ToggleMenu_f (void)
|
||||
{
|
||||
m_entersound = true;
|
||||
|
||||
if (key_dest == key_menu)
|
||||
{
|
||||
key_dest = key_game;
|
||||
m_state = m_none;
|
||||
return;
|
||||
}
|
||||
if (key_dest == key_console)
|
||||
{
|
||||
if (cls.state != ca_active)
|
||||
M_Menu_Main_f();
|
||||
else
|
||||
Con_ToggleConsole_f ();
|
||||
}
|
||||
else
|
||||
{
|
||||
M_Menu_Main_f ();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
/* OPTIONS MENU */
|
||||
#define SLIDER_RANGE 10
|
||||
|
||||
void M_DrawSlider (int x, int y, float range)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (range < 0)
|
||||
range = 0;
|
||||
if (range > 1)
|
||||
range = 1;
|
||||
M_DrawCharacter (x-8, y, 128);
|
||||
for (i=0 ; i<SLIDER_RANGE ; i++)
|
||||
M_DrawCharacter (x + i*8, y, 129);
|
||||
M_DrawCharacter (x+i*8, y, 130);
|
||||
M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131);
|
||||
}
|
||||
|
||||
void M_DrawCheckbox (int x, int y, int on)
|
||||
{
|
||||
#if 0
|
||||
if (on)
|
||||
M_DrawCharacter (x, y, 131);
|
||||
else
|
||||
M_DrawCharacter (x, y, 129);
|
||||
#endif
|
||||
if (on)
|
||||
M_Print (x, y, "on");
|
||||
else
|
||||
M_Print (x, y, "off");
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
/* KEYS MENU */
|
||||
|
||||
typedef struct {
|
||||
char *command;
|
||||
char *name;
|
||||
} bindnames_t;
|
||||
|
||||
bindnames_t qwbindnames[] =
|
||||
{
|
||||
{"+attack", "attack"},
|
||||
{"impulse 10", "change weapon"},
|
||||
{"+jump", "jump / swim up"},
|
||||
{"+forward", "walk forward"},
|
||||
{"+back", "backpedal"},
|
||||
{"+left", "turn left"},
|
||||
{"+right", "turn right"},
|
||||
{"+speed", "run"},
|
||||
{"+moveleft", "step left"},
|
||||
{"+moveright", "step right"},
|
||||
{"+strafe", "sidestep"},
|
||||
{"+lookup", "look up"},
|
||||
{"+lookdown", "look down"},
|
||||
{"centerview", "center view"},
|
||||
{"+mlook", "mouse look"},
|
||||
{"+klook", "keyboard look"},
|
||||
{"+moveup", "swim up"},
|
||||
{"+movedown", "swim down"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
#ifdef Q2CLIENT
|
||||
bindnames_t q2bindnames[] =
|
||||
{
|
||||
{"+attack", "attack"},
|
||||
{"cmd weapnext", "next weapon"},
|
||||
{"+forward", "walk forward"},
|
||||
{"+back", "backpedal"},
|
||||
{"+left", "turn left"},
|
||||
{"+right", "turn right"},
|
||||
{"+speed", "run"},
|
||||
{"+moveleft", "step left"},
|
||||
{"+moveright", "step right"},
|
||||
{"+strafe", "sidestep"},
|
||||
{"+lookup", "look up"},
|
||||
{"+lookdown", "look down"},
|
||||
{"centerview", "center view"},
|
||||
{"+mlook", "mouse look"},
|
||||
{"+klook", "keyboard look"},
|
||||
{"+moveup", "up / jump"},
|
||||
{"+movedown", "down / crouch"},
|
||||
|
||||
{"cmd inven", "inventory"},
|
||||
{"cmd invuse", "use item"},
|
||||
{"cmd invdrop", "drop item"},
|
||||
{"cmd invprev", "prev item"},
|
||||
{"cmd invnext", "next item"},
|
||||
|
||||
{"cmd help", "help computer" },
|
||||
{NULL}
|
||||
};
|
||||
#endif
|
||||
|
||||
bindnames_t *bindnames;
|
||||
int numbindnames;
|
||||
|
||||
int keys_cursor;
|
||||
int bind_grab;
|
||||
|
||||
void M_Menu_Keys_f (void)
|
||||
{
|
||||
key_dest = key_menu;
|
||||
m_state = m_keys;
|
||||
m_entersound = true;
|
||||
|
||||
#ifdef Q2CLIENT
|
||||
if (cls.q2server)
|
||||
bindnames = q2bindnames;
|
||||
else
|
||||
#endif
|
||||
bindnames = qwbindnames;
|
||||
|
||||
for (numbindnames=0 ; ; numbindnames++)
|
||||
{
|
||||
if (!bindnames[numbindnames].command)
|
||||
break;
|
||||
}
|
||||
|
||||
if (keys_cursor >= numbindnames)
|
||||
keys_cursor = 0;
|
||||
}
|
||||
|
||||
|
||||
void M_FindKeysForCommand (char *command, int *twokeys)
|
||||
{
|
||||
int count;
|
||||
int j;
|
||||
int l;
|
||||
char *b;
|
||||
|
||||
twokeys[0] = twokeys[1] = -1;
|
||||
l = strlen(command);
|
||||
count = 0;
|
||||
|
||||
for (j=0 ; j<256 ; j++)
|
||||
{
|
||||
b = keybindings[j][0];
|
||||
if (!b)
|
||||
continue;
|
||||
if (!strncmp (b, command, l) )
|
||||
{
|
||||
twokeys[count] = j;
|
||||
count++;
|
||||
if (count == 2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void M_UnbindCommand (char *command)
|
||||
{
|
||||
int j;
|
||||
int l;
|
||||
char *b;
|
||||
|
||||
l = strlen(command);
|
||||
|
||||
for (j=0 ; j<256 ; j++)
|
||||
{
|
||||
b = keybindings[j][0];
|
||||
if (!b)
|
||||
continue;
|
||||
if (!strncmp (b, command, l) )
|
||||
Key_SetBinding (j, ~0, "", RESTRICT_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_Keys_Draw (void)
|
||||
{
|
||||
int i, l;
|
||||
int keys[2];
|
||||
char *name;
|
||||
int x, y;
|
||||
qpic_t *p;
|
||||
|
||||
p = Draw_SafeCachePic ("gfx/ttl_cstm.lmp");
|
||||
if (p)
|
||||
M_DrawPic ( (320-p->width)/2, 4, p);
|
||||
|
||||
if (bind_grab)
|
||||
M_Print (12, 32, "Press a key or button for this action");
|
||||
else
|
||||
M_Print (18, 32, "Enter to change, backspace to clear");
|
||||
|
||||
// search for known bindings
|
||||
for (i=0 ; ; i++)
|
||||
{
|
||||
if (!bindnames[i].command)
|
||||
break;
|
||||
y = 48 + 8*i;
|
||||
|
||||
M_Print (16, y, bindnames[i].name);
|
||||
|
||||
l = strlen (bindnames[i].command);
|
||||
|
||||
M_FindKeysForCommand (bindnames[i].command, keys);
|
||||
|
||||
if (keys[0] == -1)
|
||||
{
|
||||
M_Print (140, y, "???");
|
||||
}
|
||||
else
|
||||
{
|
||||
name = Key_KeynumToString (keys[0]);
|
||||
M_Print (140, y, name);
|
||||
x = strlen(name) * 8;
|
||||
if (keys[1] != -1)
|
||||
{
|
||||
M_Print (140 + x + 8, y, "or");
|
||||
M_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bind_grab)
|
||||
M_DrawCharacter (130, 48 + keys_cursor*8, '=');
|
||||
else
|
||||
M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
|
||||
}
|
||||
|
||||
|
||||
void M_Keys_Key (int k)
|
||||
{
|
||||
char cmd[80];
|
||||
int keys[2];
|
||||
|
||||
if (bind_grab)
|
||||
{ // defining a key
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
if (k == K_ESCAPE)
|
||||
{
|
||||
bind_grab = false;
|
||||
}
|
||||
else if (k != '`')
|
||||
{
|
||||
sprintf (cmd, "bind %s \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor].command);
|
||||
Cbuf_InsertText (cmd, RESTRICT_LOCAL);
|
||||
}
|
||||
|
||||
bind_grab = false;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (k)
|
||||
{
|
||||
case K_ESCAPE:
|
||||
M_Menu_Options_f ();
|
||||
break;
|
||||
|
||||
case K_LEFTARROW:
|
||||
case K_UPARROW:
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
keys_cursor--;
|
||||
if (keys_cursor < 0)
|
||||
keys_cursor = numbindnames-1;
|
||||
break;
|
||||
|
||||
case K_DOWNARROW:
|
||||
case K_RIGHTARROW:
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
keys_cursor++;
|
||||
if (keys_cursor >= numbindnames)
|
||||
keys_cursor = 0;
|
||||
break;
|
||||
|
||||
case K_ENTER: // go into bind mode
|
||||
M_FindKeysForCommand (bindnames[keys_cursor].command, keys);
|
||||
S_LocalSound ("misc/menu2.wav");
|
||||
if (keys[1] != -1)
|
||||
M_UnbindCommand (bindnames[keys_cursor].command);
|
||||
bind_grab = true;
|
||||
break;
|
||||
|
||||
case K_BACKSPACE: // delete bindings
|
||||
case K_DEL: // delete bindings
|
||||
S_LocalSound ("misc/menu2.wav");
|
||||
M_UnbindCommand (bindnames[keys_cursor].command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
/* HELP MENU */
|
||||
|
||||
int help_page;
|
||||
char *helpstyle;
|
||||
int num_help_pages;
|
||||
int helppagemin;
|
||||
|
||||
|
||||
void M_Menu_Help_f (void)
|
||||
{
|
||||
key_dest = key_menu;
|
||||
m_state = m_help;
|
||||
m_entersound = true;
|
||||
help_page = 0;
|
||||
|
||||
if (COM_FDepthFile("gfx/help1.lmp", true) < COM_FDepthFile("gfx/menu/help1.lmp", true))
|
||||
{
|
||||
helpstyle = "gfx/help%i.lmp";
|
||||
num_help_pages = 6;
|
||||
helppagemin=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
helpstyle = "gfx/menu/help%02i.lmp";
|
||||
num_help_pages = 5;
|
||||
helppagemin = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void M_Help_Draw (void)
|
||||
{
|
||||
qpic_t *pic;
|
||||
pic = Draw_SafeCachePic(va(helpstyle, help_page+helppagemin));
|
||||
if (!pic)
|
||||
M_Menu_Main_f ();
|
||||
else
|
||||
M_DrawPic (0, 0, pic);
|
||||
}
|
||||
|
||||
|
||||
void M_Help_Key (int key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case K_ESCAPE:
|
||||
M_Menu_Main_f ();
|
||||
break;
|
||||
|
||||
case K_UPARROW:
|
||||
case K_RIGHTARROW:
|
||||
m_entersound = true;
|
||||
if (++help_page >= num_help_pages)
|
||||
help_page = 0;
|
||||
break;
|
||||
|
||||
case K_DOWNARROW:
|
||||
case K_LEFTARROW:
|
||||
m_entersound = true;
|
||||
if (--help_page < 0)
|
||||
help_page = num_help_pages-1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
/* QUIT MENU */
|
||||
|
||||
int msgNumber;
|
||||
int m_quit_prevstate;
|
||||
qboolean wasInMenus;
|
||||
|
||||
char *quitMessage [] =
|
||||
{
|
||||
/* .........1.........2.... */
|
||||
" Are you gonna quit ",
|
||||
" this game just like ",
|
||||
" everything else? ",
|
||||
" ",
|
||||
|
||||
" Milord, methinks that ",
|
||||
" thou art a lowly ",
|
||||
" quitter. Is this true? ",
|
||||
" ",
|
||||
|
||||
" Do I need to bust your ",
|
||||
" face open for trying ",
|
||||
" to quit? ",
|
||||
" ",
|
||||
|
||||
" Man, I oughta smack you",
|
||||
" for trying to quit! ",
|
||||
" Press Y to get ",
|
||||
" smacked out. ",
|
||||
|
||||
" Press Y to quit like a ",
|
||||
" big loser in life. ",
|
||||
" Press N to stay proud ",
|
||||
" and successful! ",
|
||||
|
||||
" If you press Y to ",
|
||||
" quit, I will summon ",
|
||||
" Satan all over your ",
|
||||
" hard drive! ",
|
||||
|
||||
" Um, Asmodeus dislikes ",
|
||||
" his children trying to ",
|
||||
" quit. Press Y to return",
|
||||
" to your Tinkertoys. ",
|
||||
|
||||
" If you quit now, I'll ",
|
||||
" throw a blanket-party ",
|
||||
" for you next time! ",
|
||||
" "
|
||||
};
|
||||
/*
|
||||
void OldM_Menu_Quit_f (void)
|
||||
{
|
||||
if (m_state == m_quit)
|
||||
return;
|
||||
wasInMenus = (key_dest == key_menu);
|
||||
key_dest = key_menu;
|
||||
m_quit_prevstate = m_state;
|
||||
m_state = m_quit;
|
||||
m_entersound = true;
|
||||
msgNumber = rand()&7;
|
||||
}
|
||||
|
||||
|
||||
void M_Quit_Key (int key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case K_ESCAPE:
|
||||
case 'n':
|
||||
case 'N':
|
||||
if (wasInMenus)
|
||||
{
|
||||
m_state = m_quit_prevstate;
|
||||
m_entersound = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
key_dest = key_game;
|
||||
m_state = m_none;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
case 'y':
|
||||
key_dest = key_console;
|
||||
CL_Disconnect ();
|
||||
Sys_Quit ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void M_Quit_Draw (void)
|
||||
{
|
||||
#define VSTR(x) #x
|
||||
#define VSTR2(x) VSTR(x)
|
||||
char *cmsg[] = {
|
||||
// 0123456789012345678901234567890123456789
|
||||
"0 QuakeWorld",
|
||||
"1 version " VSTR2(VERSION),
|
||||
"1modified by Forethought Entertainment",
|
||||
"0Based on QuakeWorld Version 2.40",
|
||||
"1",
|
||||
"0Additional Programming",
|
||||
"1 David Walton",
|
||||
"1",
|
||||
"0Id Software is not responsible for",
|
||||
"0providing technical support for",
|
||||
"0QUAKEWORLD(tm). (c)1996 Id Software,",
|
||||
"0Inc. All Rights Reserved.",
|
||||
"0QUAKEWORLD(tm) is a trademark of Id",
|
||||
"0Software, Inc.",
|
||||
"1NOTICE: THE COPYRIGHT AND TRADEMARK",
|
||||
"1NOTICES APPEARING IN YOUR COPY OF",
|
||||
"1QUAKE(r) ARE NOT MODIFIED BY THE USE",
|
||||
"1OF QUAKEWORLD(tm) AND REMAIN IN FULL",
|
||||
"1FORCE.",
|
||||
"0NIN(r) is a registered trademark",
|
||||
"0licensed to Nothing Interactive, Inc.",
|
||||
"0All rights reserved. Press y to exit",
|
||||
NULL };
|
||||
char **p;
|
||||
int y;
|
||||
|
||||
if (wasInMenus)
|
||||
{
|
||||
m_state = m_quit_prevstate;
|
||||
m_recursiveDraw = true;
|
||||
M_Draw ();
|
||||
m_state = m_quit;
|
||||
}
|
||||
#if 1
|
||||
M_DrawTextBox (0, 0, 38, 23);
|
||||
y = 12;
|
||||
for (p = cmsg; *p; p++, y += 8) {
|
||||
if (**p == '0')
|
||||
M_PrintWhite (16, y, *p + 1);
|
||||
else
|
||||
M_Print (16, y, *p + 1);
|
||||
}
|
||||
#else
|
||||
M_DrawTextBox (56, 76, 24, 4);
|
||||
M_Print (64, 84, quitMessage[msgNumber*4+0]);
|
||||
M_Print (64, 92, quitMessage[msgNumber*4+1]);
|
||||
M_Print (64, 100, quitMessage[msgNumber*4+2]);
|
||||
M_Print (64, 108, quitMessage[msgNumber*4+3]);
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
qboolean MC_Quit_Key (int key, menu_t *menu)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case K_ESCAPE:
|
||||
case 'n':
|
||||
case 'N':
|
||||
M_RemoveMenu(menu);
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
case 'y':
|
||||
M_RemoveMenu(menu);
|
||||
key_dest = key_console;
|
||||
CL_Disconnect ();
|
||||
Sys_Quit ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
menu_t quitmenu;
|
||||
void M_Menu_Quit_f (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
CL_Disconnect ();
|
||||
Sys_Quit ();
|
||||
|
||||
key_dest = key_menu;
|
||||
m_state = m_complex;
|
||||
m_entersound = true;
|
||||
|
||||
M_RemoveMenu(&quitmenu);
|
||||
memset(&quitmenu, 0, sizeof(quitmenu));
|
||||
M_AddMenuFront(&quitmenu);
|
||||
quitmenu.exclusive = false;
|
||||
quitmenu.key = MC_Quit_Key;
|
||||
|
||||
|
||||
i = rand()&7;
|
||||
|
||||
MC_AddWhiteText(&quitmenu, 64, 84, quitMessage[i*4+0], false);
|
||||
MC_AddWhiteText(&quitmenu, 64, 92, quitMessage[i*4+1], false);
|
||||
MC_AddWhiteText(&quitmenu, 64, 100, quitMessage[i*4+2], false);
|
||||
MC_AddWhiteText(&quitmenu, 64, 108, quitMessage[i*4+3], false);
|
||||
MC_AddBox (&quitmenu, 56, 76, 24, 4);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
/* Menu Subsystem */
|
||||
|
||||
|
||||
void M_OptionsMenusInit (void);
|
||||
void M_Menu_MediaFiles_f (void);
|
||||
void M_Init (void)
|
||||
{
|
||||
Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
|
||||
#ifndef CLIENTONLY
|
||||
Cmd_AddCommand ("menu_save", M_Menu_Save_f);
|
||||
Cmd_AddCommand ("menu_load", M_Menu_Load_f);
|
||||
#endif
|
||||
Cmd_AddCommand ("menu_single", M_Menu_SinglePlayer_f);
|
||||
Cmd_AddCommand ("menu_multi", M_Menu_MultiPlayer_f);
|
||||
Cmd_AddCommand ("menu_demo", M_Menu_Demos_f);
|
||||
|
||||
Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
|
||||
Cmd_AddCommand ("help", M_Menu_Help_f);
|
||||
Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
|
||||
Cmd_AddCommand ("menu_media", M_Menu_Media_f);
|
||||
Cmd_AddCommand ("menu_mediafiles", M_Menu_MediaFiles_f);
|
||||
|
||||
#ifdef CL_MASTER
|
||||
Cmd_AddCommand ("menu_servers", M_Menu_ServerList_f);
|
||||
Cmd_AddCommand ("menu_slist", M_Menu_ServerList_f);
|
||||
#endif
|
||||
Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
|
||||
Cmd_AddCommand ("menu_newmulti", M_Menu_GameOptions_f);
|
||||
|
||||
|
||||
Cmd_AddCommand ("menu_main", M_Menu_Main_f); //I've moved main to last because that way tab give us main and not quit.
|
||||
|
||||
M_OptionsMenusInit();
|
||||
|
||||
Cvar_Register(&m_helpismedia, "Menu thingumiebobs");
|
||||
|
||||
Media_Init();
|
||||
#ifdef CL_MASTER
|
||||
M_Serverlist_Init();
|
||||
#endif
|
||||
M_Script_Init();
|
||||
|
||||
XWindows_Init();
|
||||
}
|
||||
|
||||
|
||||
void M_Draw (int uimenu)
|
||||
{
|
||||
if (uimenu)
|
||||
{
|
||||
if (uimenu == 2)
|
||||
Draw_FadeScreen ();
|
||||
|
||||
UI_DrawMenu();
|
||||
|
||||
VID_UnlockBuffer ();
|
||||
S_ExtraUpdate ();
|
||||
VID_LockBuffer ();
|
||||
}
|
||||
|
||||
if (m_state != m_complex)
|
||||
{
|
||||
M_RemoveAllMenus();
|
||||
}
|
||||
if (key_dest != key_menu)
|
||||
{
|
||||
m_state = m_none;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state == m_none)
|
||||
return;
|
||||
|
||||
if ((!menu_script || scr_con_current) && !m_recursiveDraw)
|
||||
{
|
||||
scr_copyeverything = 1;
|
||||
|
||||
if (scr_con_current)
|
||||
{
|
||||
Draw_ConsoleBackground (vid.height);
|
||||
VID_UnlockBuffer ();
|
||||
S_ExtraUpdate ();
|
||||
VID_LockBuffer ();
|
||||
}
|
||||
else
|
||||
Draw_FadeScreen ();
|
||||
|
||||
scr_fullupdate = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_recursiveDraw = false;
|
||||
}
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case m_none:
|
||||
break;
|
||||
|
||||
case m_keys:
|
||||
M_Keys_Draw ();
|
||||
break;
|
||||
|
||||
case m_help:
|
||||
M_Help_Draw ();
|
||||
break;
|
||||
|
||||
case m_slist:
|
||||
M_ServerList_Draw ();
|
||||
break;
|
||||
|
||||
case m_media:
|
||||
M_Media_Draw ();
|
||||
break;
|
||||
|
||||
case m_xwindows:
|
||||
XWindows_Draw();
|
||||
break;
|
||||
|
||||
case m_complex:
|
||||
M_Complex_Draw ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_entersound)
|
||||
{
|
||||
S_LocalSound ("misc/menu2.wav");
|
||||
m_entersound = false;
|
||||
}
|
||||
|
||||
VID_UnlockBuffer ();
|
||||
S_ExtraUpdate ();
|
||||
VID_LockBuffer ();
|
||||
}
|
||||
|
||||
|
||||
void M_Keydown (int key)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case m_none:
|
||||
key_dest = key_console;
|
||||
return;
|
||||
|
||||
case m_keys:
|
||||
M_Keys_Key (key);
|
||||
return;
|
||||
|
||||
case m_help:
|
||||
M_Help_Key (key);
|
||||
return;
|
||||
|
||||
case m_slist:
|
||||
M_ServerList_Key (key);
|
||||
return;
|
||||
|
||||
case m_media:
|
||||
M_Media_Key (key);
|
||||
return;
|
||||
|
||||
case m_xwindows:
|
||||
XWindows_Key(key);
|
||||
return;
|
||||
|
||||
case m_complex:
|
||||
M_Complex_Key (key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_Keyup (int key)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case m_xwindows:
|
||||
XWindows_Keyup(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// the net drivers should just set the apropriate bits in m_activenet,
|
||||
// instead of having the menu code look through their internal tables
|
||||
//
|
||||
#define MNET_IPX 1
|
||||
#define MNET_TCP 2
|
||||
|
||||
extern int m_activenet;
|
||||
|
||||
//
|
||||
// menus
|
||||
//
|
||||
void M_Init (void);
|
||||
void M_Keydown (int key);
|
||||
void M_Keyup (int key);
|
||||
void M_Draw (int uimenu);
|
||||
void M_ToggleMenu_f (void);
|
||||
qpic_t *M_CachePic (char *path);
|
||||
void M_DrawTextBox (int x, int y, int width, int lines);
|
||||
void M_Menu_Quit_f (void);
|
||||
|
||||
struct menu_s;
|
||||
|
||||
|
||||
|
||||
void XWindows_Draw(void);
|
||||
void XWindows_Key(int key);
|
||||
void XWindows_Keyup(int key);
|
||||
void XWindows_Init(void);
|
||||
|
||||
|
||||
|
||||
typedef enum {m_none, m_complex, m_help, m_keys, m_slist, m_media, m_xwindows} m_state_t;
|
||||
extern m_state_t m_state;
|
||||
|
||||
typedef enum {mt_childwindow, mt_button, mt_buttonbigfont, mt_box, mt_colouredbox, mt_line, mt_edit, mt_text, mt_slider, mt_combo, mt_checkbox, mt_picture, mt_menudot, mt_custom} menutype_t;
|
||||
|
||||
typedef struct { //must be first of each structure type.
|
||||
menutype_t type;
|
||||
int posx;
|
||||
int posy;
|
||||
int width;
|
||||
int height;
|
||||
qboolean iszone;
|
||||
union menuoption_s *next;
|
||||
} menucommon_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
menucommon_t common;
|
||||
const char *text;
|
||||
const char *command;
|
||||
qboolean (*key) (union menuoption_s *option, struct menu_s *, int key);
|
||||
} menubutton_t;
|
||||
|
||||
#define MAX_EDIT_LENGTH 256
|
||||
typedef struct {
|
||||
menucommon_t common;
|
||||
const char *caption;
|
||||
cvar_t *cvar;
|
||||
char text[MAX_EDIT_LENGTH];
|
||||
int cursorpos;
|
||||
} menuedit_t;
|
||||
typedef struct {
|
||||
menucommon_t common;
|
||||
float min;
|
||||
float max;
|
||||
float current;
|
||||
float smallchange;
|
||||
float largechange;
|
||||
cvar_t *var;
|
||||
const char *text;
|
||||
} menuslider_t;
|
||||
|
||||
typedef enum {CHK_CHECKED, CHK_TOGGLE} chk_set_t;
|
||||
typedef struct {
|
||||
menucommon_t common;
|
||||
const char *text;
|
||||
cvar_t *var;
|
||||
float value;
|
||||
qboolean (*func) (union menuoption_s *option, chk_set_t set);
|
||||
} menucheck_t;
|
||||
|
||||
typedef struct {
|
||||
menucommon_t common;
|
||||
const char *text;
|
||||
qboolean isred;
|
||||
} menutext_t;
|
||||
|
||||
typedef struct menucustom_s {
|
||||
menucommon_t common;
|
||||
void *data;
|
||||
void (*draw) (int x, int y, struct menucustom_s *, struct menu_s *);
|
||||
qboolean (*key) (struct menucustom_s *, struct menu_s *, int key);
|
||||
} menucustom_t;
|
||||
|
||||
typedef struct {
|
||||
menucommon_t common;
|
||||
char *picturename;
|
||||
} menupicture_t;
|
||||
|
||||
typedef struct {
|
||||
menucommon_t common;
|
||||
int width;
|
||||
int height;
|
||||
} menubox_t;
|
||||
|
||||
typedef struct {
|
||||
menucommon_t common;
|
||||
|
||||
const char *caption;
|
||||
const char **options;
|
||||
const char **values;
|
||||
cvar_t *cvar;
|
||||
int numoptions;
|
||||
int selectedoption;
|
||||
} menucombo_t;
|
||||
|
||||
typedef union menuoption_s {
|
||||
menucommon_t common;
|
||||
menubutton_t button;
|
||||
menuedit_t edit;
|
||||
menucombo_t combo;
|
||||
menuslider_t slider;
|
||||
menutext_t text;
|
||||
menucustom_t custom;
|
||||
menupicture_t picture;
|
||||
menubox_t box;
|
||||
menucheck_t check;
|
||||
} menuoption_t;
|
||||
|
||||
typedef struct menu_s {
|
||||
int xpos;
|
||||
int ypos;
|
||||
int width;
|
||||
int height;
|
||||
int numoptions;
|
||||
|
||||
qboolean iszone;
|
||||
qboolean exclusive;
|
||||
|
||||
void *data; //typecast
|
||||
|
||||
void (*remove) (struct menu_s *);
|
||||
qboolean (*key) (int key, struct menu_s *); //true if key was handled
|
||||
void (*event) (struct menu_s *);
|
||||
menuoption_t *options;
|
||||
|
||||
menuoption_t *selecteditem;
|
||||
|
||||
struct menu_s *child;
|
||||
struct menu_s *parent;
|
||||
|
||||
int cursorpos;
|
||||
menuoption_t *cursoritem;
|
||||
} menu_t;
|
||||
|
||||
menutext_t *MC_AddBufferedText(menu_t *menu, int x, int y, const char *text, qboolean rightalign, qboolean red);
|
||||
menutext_t *MC_AddRedText(menu_t *menu, int x, int y, const char *text, qboolean rightalign);
|
||||
menutext_t *MC_AddWhiteText(menu_t *menu, int x, int y, const char *text, qboolean rightalign);
|
||||
menubox_t *MC_AddBox(menu_t *menu, int x, int y, int width, int height);
|
||||
menupicture_t *MC_AddPicture(menu_t *menu, int x, int y, char *picname);
|
||||
menupicture_t *MC_AddCenterPicture(menu_t *menu, int y, char *picname);
|
||||
menupicture_t *MC_AddCursor(menu_t *menu, int x, int y);
|
||||
menuslider_t *MC_AddSlider(menu_t *menu, int x, int y, const char *text, cvar_t *var, float min, float max);
|
||||
menucheck_t *MC_AddCheckBox(menu_t *menu, int x, int y, const char *text, cvar_t *var);
|
||||
menubutton_t *MC_AddConsoleCommand(menu_t *menu, int x, int y, const char *text, const char *command);
|
||||
menubutton_t *MC_AddCommand(menu_t *menu, int x, int y, char *text, qboolean (*command) (union menuoption_s *,struct menu_s *,int));
|
||||
|
||||
menucombo_t *MC_AddCombo(menu_t *menu, int x, int y, const char *caption, const char **text, int initialvalue);
|
||||
|
||||
menubutton_t *MC_AddCommand(menu_t *menu, int x, int y, char *text, qboolean (*command) (union menuoption_s *,struct menu_s *,int));
|
||||
menuedit_t *MC_AddEdit(menu_t *menu, int x, int y, char *text, char *def);
|
||||
menuedit_t *MC_AddEditCvar(menu_t *menu, int x, int y, char *text, char *name);
|
||||
menucustom_t *MC_AddCustom(menu_t *menu, int x, int y, const char *data);
|
||||
|
||||
menu_t *M_CreateMenu (int extrasize);
|
||||
void M_AddMenu (menu_t *menu);
|
||||
void M_AddMenuFront (menu_t *menu);
|
||||
void M_HideMenu (menu_t *menu);
|
||||
void M_RemoveMenu (menu_t *menu);
|
||||
void M_RemoveAllMenus (void);
|
||||
|
||||
void M_Complex_Key(int key);
|
||||
void M_Complex_Draw(void);
|
||||
void M_Script_Init(void);
|
||||
void M_Serverlist_Init(void);
|
||||
|
||||
extern qboolean m_entersound;
|
||||
|
||||
void M_Menu_Main_f (void);
|
||||
void M_Menu_SinglePlayer_f (void);
|
||||
void M_Menu_Load_f (void);
|
||||
void M_Menu_Save_f (void);
|
||||
void M_Menu_MultiPlayer_f (void);
|
||||
void M_Menu_Setup_f (void);
|
||||
void M_Menu_Net_f (void);
|
||||
void M_Menu_Options_f (void);
|
||||
void M_Menu_Keys_f (void);
|
||||
void M_Menu_Video_f (void);
|
||||
void M_Menu_Help_f (void);
|
||||
void M_Menu_Quit_f (void);
|
||||
void M_Menu_SerialConfig_f (void);
|
||||
void M_Menu_ModemConfig_f (void);
|
||||
void M_Menu_LanConfig_f (void);
|
||||
void M_Menu_GameOptions_f (void);
|
||||
void M_Menu_Search_f (void);
|
||||
void M_Menu_ServerList_f (void);
|
||||
void M_Menu_Media_f (void);
|
||||
|
||||
void M_Main_Draw (void);
|
||||
void M_SinglePlayer_Draw (void);
|
||||
void M_Load_Draw (void);
|
||||
void M_Save_Draw (void);
|
||||
void M_MultiPlayer_Draw (void);
|
||||
void M_Setup_Draw (void);
|
||||
void M_Net_Draw (void);
|
||||
void M_Options_Draw (void);
|
||||
void M_Keys_Draw (void);
|
||||
void M_Video_Draw (void);
|
||||
void M_Help_Draw (void);
|
||||
void M_Quit_Draw (void);
|
||||
void M_SerialConfig_Draw (void);
|
||||
void M_ModemConfig_Draw (void);
|
||||
void M_LanConfig_Draw (void);
|
||||
void M_GameOptions_Draw (void);
|
||||
void M_Search_Draw (void);
|
||||
void M_ServerList_Draw (void);
|
||||
void M_Media_Draw (void);
|
||||
|
||||
void M_Main_Key (int key);
|
||||
void M_SinglePlayer_Key (int key);
|
||||
void M_Load_Key (int key);
|
||||
void M_Save_Key (int key);
|
||||
void M_MultiPlayer_Key (int key);
|
||||
void M_Setup_Key (int key);
|
||||
void M_Net_Key (int key);
|
||||
void M_Options_Key (int key);
|
||||
void M_Keys_Key (int key);
|
||||
void M_Video_Key (int key);
|
||||
void M_Help_Key (int key);
|
||||
void M_Quit_Key (int key);
|
||||
void M_SerialConfig_Key (int key);
|
||||
void M_ModemConfig_Key (int key);
|
||||
void M_LanConfig_Key (int key);
|
||||
void M_GameOptions_Key (int key);
|
||||
void M_Search_Key (int key);
|
||||
void M_ServerList_Key (int key);
|
||||
void M_Media_Key (int key);
|
||||
|
||||
void MasterInfo_Begin(void);
|
||||
void M_DrawServers(void);
|
||||
void M_SListKey(int key);
|
||||
|
||||
//drawing funcs
|
||||
void M_BuildTranslationTable(int top, int bottom);
|
||||
void M_DrawTransPicTranslate (int x, int y, qpic_t *pic);
|
||||
void M_DrawTransPic (int x, int y, qpic_t *pic);
|
||||
void M_DrawCharacter (int cx, int line, unsigned int num);
|
||||
void M_Print (int cx, int cy, qbyte *str);
|
||||
void M_PrintWhite (int cx, int cy, qbyte *str);
|
||||
void M_DrawPic (int x, int y, qpic_t *pic);
|
|
@ -0,0 +1,107 @@
|
|||
//These are defined later in the source tree. This file should probably be moved to a later spot.
|
||||
struct progfuncs_s;
|
||||
struct globalvars_s;
|
||||
struct texture_s;
|
||||
|
||||
//function prototypes
|
||||
|
||||
#if defined(SERVERONLY)
|
||||
#define qrenderer QR_NONE
|
||||
#define FNC(n) (n)
|
||||
#else
|
||||
#define FNC(n) (*n)
|
||||
extern r_qrenderer_t qrenderer;
|
||||
extern char *q_renderername;
|
||||
|
||||
|
||||
extern qpic_t *(*Draw_PicFromWad) (char *name);
|
||||
extern qpic_t *(*Draw_SafePicFromWad) (char *name);
|
||||
extern qpic_t *(*Draw_CachePic) (char *path);
|
||||
extern qpic_t *(*Draw_SafeCachePic) (char *path);
|
||||
extern void (*Draw_Init) (void);
|
||||
extern void (*Draw_ReInit) (void);
|
||||
extern void (*Draw_Character) (int x, int y, unsigned int num);
|
||||
extern void (*Draw_ColouredCharacter) (int x, int y, unsigned int num);
|
||||
extern void (*Draw_String) (int x, int y, const qbyte *str);
|
||||
extern void (*Draw_Alt_String) (int x, int y, const qbyte *str);
|
||||
extern void (*Draw_Crosshair) (void);
|
||||
extern void (*Draw_DebugChar) (qbyte num);
|
||||
extern void (*Draw_Pic) (int x, int y, qpic_t *pic);
|
||||
extern void (*Draw_ScalePic) (int x, int y, int width, int height, qpic_t *pic);
|
||||
extern void (*Draw_SubPic) (int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height);
|
||||
extern void (*Draw_TransPic) (int x, int y, qpic_t *pic);
|
||||
extern void (*Draw_TransPicTranslate) (int x, int y, qpic_t *pic, qbyte *translation);
|
||||
extern void (*Draw_ConsoleBackground) (int lines);
|
||||
extern void (*Draw_EditorBackground) (int lines);
|
||||
extern void (*Draw_TileClear) (int x, int y, int w, int h);
|
||||
extern void (*Draw_Fill) (int x, int y, int w, int h, int c);
|
||||
extern void (*Draw_FadeScreen) (void);
|
||||
extern void (*Draw_BeginDisc) (void);
|
||||
extern void (*Draw_EndDisc) (void);
|
||||
|
||||
extern void (*R_Init) (void);
|
||||
extern void (*R_DeInit) (void);
|
||||
extern void (*R_ReInit) (void);
|
||||
extern void (*R_RenderView) (void); // must set r_refdef first
|
||||
|
||||
extern void (*R_InitSky) (struct texture_s *mt); // called at level load
|
||||
extern qboolean (*R_CheckSky) (void);
|
||||
extern void (*R_SetSky) (char *name, float rotate, vec3_t axis);
|
||||
|
||||
extern void (*R_NewMap) (void);
|
||||
extern void (*R_PreNewMap) (void);
|
||||
extern int (*R_LightPoint) (vec3_t point);
|
||||
|
||||
extern void (*R_PushDlights) (void);
|
||||
extern void (*R_AddStain) (vec3_t org, float red, float green, float blue, float radius);
|
||||
extern void (*R_LessenStains) (void);
|
||||
extern void (*R_DrawWaterSurfaces) (void);
|
||||
|
||||
|
||||
extern qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
|
||||
extern void (*VID_DeInit) (void);
|
||||
extern void (*VID_HandlePause) (qboolean pause);
|
||||
extern void (*VID_LockBuffer) (void);
|
||||
extern void (*VID_UnlockBuffer) (void);
|
||||
extern void (*D_BeginDirectRect) (int x, int y, qbyte *pbitmap, int width, int height);
|
||||
extern void (*D_EndDirectRect) (int x, int y, int width, int height);
|
||||
extern void (*VID_ForceLockState) (int lk);
|
||||
extern int (*VID_ForceUnlockedAndReturnState) (void);
|
||||
extern void (*VID_SetPalette) (unsigned char *palette);
|
||||
extern void (*VID_ShiftPalette) (unsigned char *palette);
|
||||
extern char *(*VID_GetRGBInfo)(int prepad, int *truevidwidth, int *truevidheight);
|
||||
extern void (*VID_SetWindowCaption) (char *msg);
|
||||
|
||||
extern void SCR_Init (void);
|
||||
extern void SCR_DeInit (void);
|
||||
extern void (*SCR_UpdateScreen) (void);
|
||||
extern void SCR_BeginLoadingPlaque (void);
|
||||
extern void SCR_EndLoadingPlaque (void);
|
||||
extern void SCR_DrawConsole (qboolean noback);
|
||||
extern void SCR_SetUpToDrawConsole (void);
|
||||
extern void SCR_EraseCenterString (void);
|
||||
extern void SCR_CenterPrint (int pnum, char *str);
|
||||
|
||||
#endif
|
||||
|
||||
extern void FNC(Mod_Init) (void);
|
||||
extern void FNC(Mod_ClearAll) (void);
|
||||
extern struct model_s *FNC(Mod_ForName) (char *name, qboolean crash);
|
||||
extern struct model_s *FNC(Mod_FindName) (char *name);
|
||||
extern void *FNC(Mod_Extradata) (struct model_s *mod); // handles caching
|
||||
extern void FNC(Mod_TouchModel) (char *name);
|
||||
|
||||
extern struct mleaf_s *FNC(Mod_PointInLeaf) (float *p, struct model_s *model);
|
||||
extern qbyte *FNC(Mod_Q1LeafPVS) (struct mleaf_s *leaf, struct model_s *model, qbyte *buffer); //purly for q1
|
||||
extern void FNC(Mod_NowLoadExternal) (void);
|
||||
|
||||
extern void FNC(Mod_ReloadTextures) (void);
|
||||
extern void FNC(Mod_Think) (void);
|
||||
|
||||
#undef FNC
|
||||
|
||||
|
||||
#ifdef SERVERONLY
|
||||
#define Mod_Q1LeafPVS Mod_LeafPVS
|
||||
qbyte *Mod_LeafPVS (struct mleaf_s *leaf, struct model_s *model, qbyte *buffer);
|
||||
#endif
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// modelgen.h: header file for model generation program
|
||||
//
|
||||
|
||||
// *********************************************************
|
||||
// * This file must be identical in the modelgen directory *
|
||||
// * and in the Quake directory, because it's used to *
|
||||
// * pass data from one to the other via model files. *
|
||||
// *********************************************************
|
||||
|
||||
#ifdef INCLUDELIBS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "scriplib.h"
|
||||
#include "trilib.h"
|
||||
#include "lbmlib.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
#endif
|
||||
|
||||
#define ALIAS_VERSION 6
|
||||
|
||||
#define ALIAS_ONSEAM 0x0020
|
||||
|
||||
// must match definition in spritegn.h
|
||||
#ifndef SYNCTYPE_T
|
||||
#define SYNCTYPE_T
|
||||
typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
|
||||
#endif
|
||||
|
||||
typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t;
|
||||
|
||||
typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t;
|
||||
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
vec3_t scale;
|
||||
vec3_t scale_origin;
|
||||
float boundingradius;
|
||||
vec3_t eyeposition;
|
||||
int numskins;
|
||||
int skinwidth;
|
||||
int skinheight;
|
||||
int numverts;
|
||||
int numstverts;
|
||||
int numtris;
|
||||
int numframes;
|
||||
synctype_t synctype;
|
||||
int flags;
|
||||
float size;
|
||||
} mmdl_t;
|
||||
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
vec3_t scale;
|
||||
vec3_t scale_origin;
|
||||
float boundingradius;
|
||||
vec3_t eyeposition;
|
||||
int numskins;
|
||||
int skinwidth;
|
||||
int skinheight;
|
||||
int numverts;
|
||||
int numtris;
|
||||
int numframes;
|
||||
synctype_t synctype;
|
||||
int flags;
|
||||
float size;
|
||||
} dmdl_t;
|
||||
|
||||
// TODO: could be shorts
|
||||
|
||||
typedef struct {
|
||||
int onseam;
|
||||
int s;
|
||||
int t;
|
||||
} dstvert_t;
|
||||
|
||||
typedef struct {
|
||||
short s;
|
||||
short t;
|
||||
} dmd2stvert_t;
|
||||
|
||||
typedef struct dtriangle_s {
|
||||
int facesfront;
|
||||
int vertindex[3];
|
||||
} dtriangle_t;
|
||||
|
||||
typedef struct dmd2triangle_s {
|
||||
short xyz_index[3];
|
||||
short st_index[3];
|
||||
} dmd2triangle_t;
|
||||
|
||||
#define DT_FACES_FRONT 0x0010
|
||||
|
||||
// This mirrors trivert_t in trilib.h, is present so Quake knows how to
|
||||
// load this data
|
||||
|
||||
typedef struct {
|
||||
qbyte v[3];
|
||||
qbyte lightnormalindex;
|
||||
} dtrivertx_t;
|
||||
|
||||
typedef struct {
|
||||
dtrivertx_t bboxmin; // lightnormal isn't used
|
||||
dtrivertx_t bboxmax; // lightnormal isn't used
|
||||
char name[16]; // frame name from grabbing
|
||||
} daliasframe_t;
|
||||
|
||||
typedef struct {
|
||||
int numframes;
|
||||
dtrivertx_t bboxmin; // lightnormal isn't used
|
||||
dtrivertx_t bboxmax; // lightnormal isn't used
|
||||
} daliasgroup_t;
|
||||
|
||||
typedef struct {
|
||||
int numskins;
|
||||
} daliasskingroup_t;
|
||||
|
||||
typedef struct {
|
||||
float interval;
|
||||
} daliasinterval_t;
|
||||
|
||||
typedef struct {
|
||||
float interval;
|
||||
} daliasskininterval_t;
|
||||
|
||||
typedef struct {
|
||||
aliasframetype_t type;
|
||||
} daliasframetype_t;
|
||||
|
||||
typedef struct {
|
||||
aliasskintype_t type;
|
||||
} daliasskintype_t;
|
||||
|
||||
#define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I')
|
||||
#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I')
|
||||
// little-endian "IDPO"
|
||||
|
|
@ -0,0 +1,980 @@
|
|||
#include "bothdefs.h"
|
||||
|
||||
#ifdef CL_MASTER
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "cl_master.h"
|
||||
|
||||
#define NET_GAMENAME_NQ "QUAKE"
|
||||
|
||||
//rename to cl_master.c sometime
|
||||
|
||||
//the networking operates seperatly from the main code. This is so we can have full control over all parts of the server sending prints.
|
||||
//when we send status to the server, it replys with a print command. The text to print contains the serverinfo.
|
||||
//Q2's print command is a compleate 'print', while qw is just a 'p', thus we can distinguish the two easily.
|
||||
|
||||
//save favorites and allow addition of new ones from game?
|
||||
//add filters some time
|
||||
|
||||
//remove dead servers.
|
||||
//master was polled a minute ago and server was not on list - server on multiple masters would be awkward.
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winquake.h"
|
||||
#define USEIPX
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#define ECONNABORTED WSAECONNABORTED
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
|
||||
#define qerrno WSAGetLastError()
|
||||
#else
|
||||
#define qerrno errno
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
typedef int SOCKET;
|
||||
#endif
|
||||
|
||||
#ifdef AF_IPX
|
||||
#define USEIPX
|
||||
#endif
|
||||
|
||||
|
||||
//the number of servers should be limited only by memory.
|
||||
|
||||
cvar_t slist_cacheinfo = {"slist_cacheinfo", "0"}; //this proves dangerous, memory wise.
|
||||
cvar_t slist_writeserverstxt = {"slist_writeservers", "0"};
|
||||
|
||||
void CL_MasterListParse(qboolean isq2);
|
||||
void CL_QueryServers(void);
|
||||
int CL_ReadServerInfo(char *msg, int servertype, qboolean favorite);
|
||||
|
||||
master_t *master;
|
||||
player_t *mplayers;
|
||||
serverinfo_t *firstserver;
|
||||
|
||||
|
||||
#define POLLUDPSOCKETS 64 //it's big so we can have lots of messages when behind a firewall. Basically if a firewall only allows replys, and only remembers 3 servers per socket, we need this big cos it can take a while for a packet to find a fast optimised route and we might be waiting for a few secs for a reply the first time around.
|
||||
SOCKET pollsocketsUDP[POLLUDPSOCKETS];
|
||||
int lastpollsockUDP;
|
||||
|
||||
#ifdef USEIPX
|
||||
#define POLLIPXSOCKETS 2 //ipx isn't used as much. In fact, we only expect local servers to be using it. I'm not sure why I implemented it anyway.
|
||||
SOCKET pollsocketsIPX[POLLIPXSOCKETS];
|
||||
int lastpollsockIPX;
|
||||
#else
|
||||
#define POLLIPXSOCKETS 0
|
||||
#endif
|
||||
|
||||
|
||||
void NetadrToSockadr (netadr_t *a, struct sockaddr_qstorage *s);
|
||||
|
||||
|
||||
|
||||
void Master_AddMaster (char *address, int type, char *description)
|
||||
{
|
||||
netadr_t adr;
|
||||
master_t *mast;
|
||||
|
||||
if (!NET_StringToAdr(address, &adr))
|
||||
{
|
||||
Con_Printf("Failed to resolve address \"%s\"\n", address);
|
||||
}
|
||||
/*
|
||||
if (type == MT_SINGLEQW || type == MT_SINGLENQ || type == MT_SINGLEQ2) //single servers are added to the serverlist as well as the masters list
|
||||
{
|
||||
net_from = adr;
|
||||
CL_ReadServerInfo(va("\\hostname\\%s", description), MT_SINGLEQ2, true);
|
||||
// return;
|
||||
}
|
||||
*/
|
||||
if (type < MT_SINGLEQW) //broadcasts
|
||||
{
|
||||
if (adr.type == NA_IP)
|
||||
adr.type = NA_BROADCAST_IP;
|
||||
if (adr.type == NA_IPX)
|
||||
adr.type = NA_BROADCAST_IPX;
|
||||
}
|
||||
|
||||
for (mast = master; mast; mast = mast->next)
|
||||
{
|
||||
if (NET_CompareAdr(mast->adr, adr)) //already exists.
|
||||
return;
|
||||
}
|
||||
mast = Z_Malloc(sizeof(master_t)+strlen(description));
|
||||
mast->adr = adr;
|
||||
mast->type = type;
|
||||
strcpy(mast->name, description);
|
||||
|
||||
mast->next = master;
|
||||
master = mast;
|
||||
}
|
||||
|
||||
//build a linked list of masters. Doesn't duplicate addresses.
|
||||
qboolean Master_LoadMasterList (char *filename, int defaulttype, int depth)
|
||||
{
|
||||
extern char com_basedir[MAX_OSPATH];
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
char file[1024];
|
||||
char *name, *next;
|
||||
int servertype;
|
||||
|
||||
if (depth <= 0)
|
||||
return false;
|
||||
depth--;
|
||||
|
||||
f = fopen(va("%s/%s", com_basedir, filename), "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
while(fgets(line, sizeof(line)-1, f))
|
||||
{
|
||||
if (*line == '#') //comment
|
||||
continue;
|
||||
|
||||
next = COM_Parse(line);
|
||||
if (!*com_token)
|
||||
continue;
|
||||
|
||||
if (!strcmp(com_token, "file")) //special case. Add a port if you have a server named 'file'... (unlikly)
|
||||
{
|
||||
next = COM_Parse(next);
|
||||
if (!next)
|
||||
continue;
|
||||
Q_strncpyz(file, com_token, sizeof(file));
|
||||
}
|
||||
else
|
||||
*file = '\0';
|
||||
|
||||
*next = '\0';
|
||||
next++;
|
||||
name = COM_Parse(next);
|
||||
servertype = -1;
|
||||
|
||||
if (!strcmp(com_token, "single:qw"))
|
||||
servertype = MT_SINGLEQW;
|
||||
else if (!strcmp(com_token, "single:q2"))
|
||||
servertype = MT_SINGLEQ2;
|
||||
else if (!strcmp(com_token, "single:nq") || !strcmp(com_token, "single:q1"))
|
||||
servertype = MT_SINGLENQ;
|
||||
else if (!strcmp(com_token, "single"))
|
||||
servertype = MT_SINGLEQW;
|
||||
|
||||
else if (!strcmp(com_token, "master:qw"))
|
||||
servertype = MT_MASTERQW;
|
||||
else if (!strcmp(com_token, "master:q2"))
|
||||
servertype = MT_MASTERQ2;
|
||||
else if (!strcmp(com_token, "master")) //any other sort of master, assume it's a qw master.
|
||||
servertype = MT_MASTERQW;
|
||||
|
||||
else if (!strcmp(com_token, "bcast:qw"))
|
||||
servertype = MT_BCASTQW;
|
||||
else if (!strcmp(com_token, "bcast:q2"))
|
||||
servertype = MT_BCASTQ2;
|
||||
else if (!strcmp(com_token, "bcast:nq"))
|
||||
servertype = MT_BCASTNQ;
|
||||
else if (!strcmp(com_token, "bcast"))
|
||||
servertype = MT_BCASTQW;
|
||||
|
||||
else if (!strcmp(com_token, "favorite:qw"))
|
||||
servertype = -MT_SINGLEQW;
|
||||
else if (!strcmp(com_token, "favorite:q2"))
|
||||
servertype = -MT_SINGLEQ2;
|
||||
else if (!strcmp(com_token, "favorite:nq"))
|
||||
servertype = -MT_SINGLENQ;
|
||||
else if (!strcmp(com_token, "favorite"))
|
||||
servertype = -MT_SINGLEQW;
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
name = next; //go back one token.
|
||||
servertype = defaulttype;
|
||||
}
|
||||
|
||||
while(*name <= ' ' && *name != 0) //skip whitespace
|
||||
name++;
|
||||
|
||||
next = name + strlen(name)-1;
|
||||
while(*next <= ' ' && next > name)
|
||||
{
|
||||
*next = '\0';
|
||||
next--;
|
||||
}
|
||||
|
||||
|
||||
if (*file)
|
||||
Master_LoadMasterList(file, servertype, depth);
|
||||
else if (servertype < 0)
|
||||
{
|
||||
if (NET_StringToAdr(line, &net_from))
|
||||
CL_ReadServerInfo(va("\\hostname\\%s", name), -servertype, true);
|
||||
else
|
||||
Con_Printf("Failed to resolve address - \"%s\"\n", line);
|
||||
}
|
||||
else
|
||||
Master_AddMaster(line, servertype, name);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void NET_SendPollPacket(int len, void *data, netadr_t to)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr_qstorage addr;
|
||||
|
||||
NetadrToSockadr (&to, &addr);
|
||||
#ifdef USEIPX
|
||||
if (addr.sa_family == AF_IPX)
|
||||
{
|
||||
lastpollsockIPX++;
|
||||
if (lastpollsockIPX>=POLLIPXSOCKETS)
|
||||
lastpollsockIPX=0;
|
||||
if (!pollsocketsIPX[lastpollsockIPX])
|
||||
pollsocketsIPX[lastpollsockIPX] = IPX_OpenSocket(PORT_ANY, true);
|
||||
ret = sendto (pollsocketsIPX[lastpollsockIPX], data, len, 0, (struct sockaddr *)&addr, sizeof(addr) );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
lastpollsockUDP++;
|
||||
if (lastpollsockUDP>=POLLUDPSOCKETS)
|
||||
lastpollsockUDP=0;
|
||||
if (!pollsocketsUDP[lastpollsockUDP])
|
||||
pollsocketsUDP[lastpollsockUDP] = UDP_OpenSocket(PORT_ANY, true);
|
||||
ret = sendto (pollsocketsUDP[lastpollsockUDP], data, len, 0, (struct sockaddr *)&addr, sizeof(addr) );
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
// wouldblock is silent
|
||||
if (qerrno == EWOULDBLOCK)
|
||||
return;
|
||||
|
||||
if (qerrno == ECONNREFUSED)
|
||||
return;
|
||||
|
||||
if (qerrno == EADDRNOTAVAIL)
|
||||
Con_DPrintf("NET_SendPacket Warning: %i\n", qerrno);
|
||||
else
|
||||
Con_Printf ("NET_SendPacket ERROR: %i\n", qerrno);
|
||||
}
|
||||
}
|
||||
|
||||
int NET_CheckPollSockets(void)
|
||||
{
|
||||
#define MAX_UDP_PACKET 8192 // one more than msg + header
|
||||
extern qbyte net_message_buffer[MAX_UDP_PACKET];
|
||||
int sock;
|
||||
SOCKET usesocket;
|
||||
for (sock = 0; sock < POLLUDPSOCKETS+POLLIPXSOCKETS; sock++)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr_qstorage from;
|
||||
int fromlen;
|
||||
|
||||
#ifdef USEIPX
|
||||
if (sock >= POLLUDPSOCKETS)
|
||||
usesocket = pollsocketsIPX[sock-POLLUDPSOCKETS];
|
||||
else
|
||||
#endif
|
||||
usesocket = pollsocketsUDP[sock];
|
||||
|
||||
if (!usesocket)
|
||||
continue;
|
||||
fromlen = sizeof(from);
|
||||
ret = recvfrom (usesocket, (char *)net_message_buffer, sizeof(net_message_buffer), 0, (struct sockaddr *)&from, &fromlen);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (qerrno == EWOULDBLOCK)
|
||||
continue;
|
||||
if (qerrno == EMSGSIZE)
|
||||
{
|
||||
SockadrToNetadr (&from, &net_from);
|
||||
Con_Printf ("Warning: Oversize packet from %s\n",
|
||||
NET_AdrToString (net_from));
|
||||
continue;
|
||||
}
|
||||
if (qerrno == ECONNABORTED || qerrno == ECONNRESET)
|
||||
{
|
||||
// Con_Printf ("Connection lost or aborted\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Con_Printf ("NET_CheckPollSockets: %s", strerror(qerrno));
|
||||
continue;
|
||||
}
|
||||
SockadrToNetadr (&from, &net_from);
|
||||
|
||||
net_message.cursize = ret;
|
||||
if (ret == sizeof(net_message_buffer) )
|
||||
{
|
||||
Con_Printf ("Oversize packet from %s\n", NET_AdrToString (net_from));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*(int *)net_message.data == -1)
|
||||
{
|
||||
int c;
|
||||
char *s;
|
||||
MSG_BeginReading ();
|
||||
MSG_ReadLong (); // skip the -1
|
||||
|
||||
#ifdef Q2CLIENT
|
||||
c = msg_readcount;
|
||||
s = MSG_ReadStringLine(); //peek for q2 messages.
|
||||
if (!strcmp(s, "print"))
|
||||
{
|
||||
CL_ReadServerInfo(MSG_ReadString(), MT_SINGLEQ2, false);
|
||||
continue;
|
||||
}
|
||||
else if (!strcmp(s, "info")) //parse a bit more...
|
||||
{
|
||||
CL_ReadServerInfo(MSG_ReadString(), MT_SINGLEQ2, false);
|
||||
continue;
|
||||
}
|
||||
else if (!strncmp(s, "servers", 6)) //parse a bit more...
|
||||
{
|
||||
msg_readcount = c+7;
|
||||
CL_MasterListParse(true);
|
||||
continue;
|
||||
}
|
||||
msg_readcount = c;
|
||||
#endif
|
||||
|
||||
c = MSG_ReadByte ();
|
||||
|
||||
if (c == A2C_PRINT) //qw server reply.
|
||||
{
|
||||
CL_ReadServerInfo(MSG_ReadString(), MT_SINGLEQW, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == M2C_MASTER_REPLY) //qw master reply.
|
||||
{
|
||||
CL_MasterListParse(false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#ifdef NQPROT
|
||||
else
|
||||
{ //connected packet? Must be a NQ packet.
|
||||
char name[32];
|
||||
char map[16];
|
||||
int users, maxusers;
|
||||
|
||||
int control;
|
||||
|
||||
MSG_BeginReading ();
|
||||
control = BigLong(*((int *)net_message.data));
|
||||
MSG_ReadLong();
|
||||
if (control == -1)
|
||||
continue;
|
||||
if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
|
||||
continue;
|
||||
if ((control & NETFLAG_LENGTH_MASK) != ret)
|
||||
continue;
|
||||
|
||||
if (MSG_ReadByte() != CCREP_SERVER_INFO)
|
||||
continue;
|
||||
|
||||
NET_StringToAdr(MSG_ReadString(), &net_from);
|
||||
|
||||
Q_strncpyz(name, MSG_ReadString(), sizeof(name));
|
||||
Q_strncpyz(map, MSG_ReadString(), sizeof(map));
|
||||
users = MSG_ReadByte();
|
||||
maxusers = MSG_ReadByte();
|
||||
if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
|
||||
{
|
||||
// Q_strcpy(name, "*");
|
||||
// Q_strcat(name, name);
|
||||
}
|
||||
|
||||
CL_ReadServerInfo(va("\\hostname\\%s\\map\\%s\\maxclients\\%i", name, map, maxusers), MT_SINGLENQ, false);
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Master_RemoveKeepInfo(serverinfo_t *sv)
|
||||
{
|
||||
sv->special &= ~SS_KEEPINFO;
|
||||
if (sv->moreinfo)
|
||||
{
|
||||
Z_Free(sv->moreinfo);
|
||||
sv->moreinfo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SListOptionChanged(serverinfo_t *newserver)
|
||||
{
|
||||
if (selectedserver.inuse)
|
||||
{
|
||||
char data[16];
|
||||
serverinfo_t *oldserver;
|
||||
|
||||
selectedserver.detail = NULL;
|
||||
|
||||
if (!slist_cacheinfo.value) //we have to flush it. That's the rules.
|
||||
{
|
||||
for (oldserver = firstserver; oldserver; oldserver=oldserver->next)
|
||||
{
|
||||
if (NET_CompareAdr(selectedserver.adr, oldserver->adr))//*(int*)selectedserver.ipaddress == *(int*)server->ipaddress && selectedserver.port == server->port)
|
||||
{
|
||||
if (oldserver->moreinfo)
|
||||
{
|
||||
Z_Free(oldserver->moreinfo);
|
||||
oldserver->moreinfo = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!newserver)
|
||||
return;
|
||||
|
||||
selectedserver.adr = newserver->adr;
|
||||
|
||||
if (newserver->moreinfo) //we cached it.
|
||||
{
|
||||
selectedserver.detail = newserver->moreinfo;
|
||||
return;
|
||||
}
|
||||
//we don't know all the info, so send a request for it.
|
||||
selectedserver.detail = newserver->moreinfo = Z_Malloc(sizeof(serverdetailedinfo_t));
|
||||
|
||||
newserver->moreinfo->numplayers = newserver->players;
|
||||
strcpy(newserver->moreinfo->info, "");
|
||||
Info_SetValueForKey(newserver->moreinfo->info, "hostname", newserver->name, sizeof(newserver->moreinfo->info));
|
||||
|
||||
newserver->refreshtime = Sys_DoubleTime();
|
||||
sprintf(data, "%c%c%c%cstatus", 255, 255, 255, 255);
|
||||
NET_SendPollPacket (strlen(data), data, newserver->adr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//don't try sending to servers we don't support
|
||||
void MasterInfo_Request(master_t *mast)
|
||||
{
|
||||
if (!mast)
|
||||
return;
|
||||
switch(mast->type)
|
||||
{
|
||||
#ifdef Q2CLIENT
|
||||
case MT_BCASTQ2:
|
||||
case MT_SINGLEQ2:
|
||||
#endif
|
||||
case MT_SINGLEQW:
|
||||
case MT_BCASTQW:
|
||||
NET_SendPollPacket (11, va("%c%c%c%cstatus\n", 255, 255, 255, 255), mast->adr);
|
||||
break;
|
||||
#ifdef NQPROT
|
||||
case MT_BCASTNQ:
|
||||
case MT_SINGLENQ:
|
||||
SZ_Clear(&net_message);
|
||||
MSG_WriteLong(&net_message, 0);// save space for the header, filled in later
|
||||
MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
|
||||
MSG_WriteString(&net_message, NET_GAMENAME_NQ); //look for either sort of server
|
||||
MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
|
||||
*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
|
||||
NET_SendPollPacket(net_message.cursize, net_message.data, mast->adr);
|
||||
SZ_Clear(&net_message);
|
||||
break;
|
||||
#endif
|
||||
case MT_MASTERQW:
|
||||
NET_SendPollPacket (3, "c\n", mast->adr);
|
||||
break;
|
||||
#ifdef Q2CLIENT
|
||||
case MT_MASTERQ2:
|
||||
if (COM_FDepthFile("pics/colormap.pcx", true)!=0x7fffffff) //only query this master if we expect to be able to load it's maps.
|
||||
NET_SendPollPacket (6, "query", mast->adr);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MasterInfo_WriteServers(void)
|
||||
{
|
||||
char *typename;
|
||||
master_t *mast;
|
||||
serverinfo_t *server;
|
||||
FILE *mf, *qws;
|
||||
|
||||
mf = fopen("masters.txt", "wt");
|
||||
if (!mf)
|
||||
{
|
||||
Con_Printf("Couldn't write masters.txt");
|
||||
return;
|
||||
}
|
||||
|
||||
for (mast = master; mast; mast=mast->next)
|
||||
{
|
||||
switch(mast->type)
|
||||
{
|
||||
case MT_MASTERQW:
|
||||
typename = "master:qw";
|
||||
break;
|
||||
case MT_MASTERQ2:
|
||||
typename = "master:q2";
|
||||
break;
|
||||
case MT_BCASTQW:
|
||||
typename = "bcast:qw";
|
||||
break;
|
||||
case MT_BCASTQ2:
|
||||
typename = "bcast:q2";
|
||||
break;
|
||||
case MT_BCASTNQ:
|
||||
typename = "bcast:nq";
|
||||
break;
|
||||
case MT_SINGLEQW:
|
||||
typename = "single:qw";
|
||||
break;
|
||||
case MT_SINGLEQ2:
|
||||
typename = "single:q2";
|
||||
break;
|
||||
case MT_SINGLENQ:
|
||||
typename = "single:nq";
|
||||
break;
|
||||
default:
|
||||
typename = "writeerror";
|
||||
}
|
||||
fprintf(mf, "%s\t%s\t%s\n", NET_AdrToString(mast->adr), typename, mast->name);
|
||||
}
|
||||
|
||||
if (slist_writeserverstxt.value)
|
||||
qws = fopen("server.txt", "wt");
|
||||
else
|
||||
qws = NULL;
|
||||
if (qws)
|
||||
fprintf(mf, "\n%s\t%s\t%s\n\n", "file servers.txt", "favorite:qw", "personal server list");
|
||||
|
||||
for (server = firstserver; server; server = server->next)
|
||||
{
|
||||
if (server->special & SS_FAVORITE)
|
||||
{
|
||||
if (server->special & SS_QUAKE2)
|
||||
fprintf(mf, "%s\t%s\t%s\n", NET_AdrToString(server->adr), "favorite:q2", server->name);
|
||||
else if (server->special & SS_NETQUAKE)
|
||||
fprintf(mf, "%s\t%s\t%s\n", NET_AdrToString(server->adr), "favorite:nq", server->name);
|
||||
else if (qws) //servers.txt doesn't support the extra info.
|
||||
fprintf(qws, "%s\t%s\n", NET_AdrToString(server->adr), server->name);
|
||||
else //read only? damn them!
|
||||
fprintf(mf, "%s\t%s\t%s\n", NET_AdrToString(server->adr), "favorite:qw", server->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (qws)
|
||||
fclose(qws);
|
||||
|
||||
|
||||
fclose(mf);
|
||||
}
|
||||
|
||||
//poll master servers for server lists.
|
||||
void MasterInfo_Begin(void)
|
||||
{
|
||||
master_t *mast;
|
||||
if (!Master_LoadMasterList("masters.txt", MT_MASTERQW, 5))
|
||||
{
|
||||
Master_LoadMasterList("servers.txt", MT_SINGLEQW, 1);
|
||||
// if (q1servers)
|
||||
{
|
||||
Master_AddMaster("255.255.255.255:26000", MT_BCASTNQ, "Nearby Quake1 servers");
|
||||
Master_AddMaster("255.255.255.255:27500", MT_BCASTQW, "Nearby QuakeWorld UDP servers.");
|
||||
}
|
||||
|
||||
// if (q2servers)
|
||||
{
|
||||
Master_AddMaster("255.255.255.255:27910", MT_BCASTQ2, "Nearby Quake2 UDP servers.");
|
||||
Master_AddMaster("00000000:ffffffffffff:27910", MT_BCASTQ2, "Nearby Quake2 IPX servers.");
|
||||
}
|
||||
|
||||
|
||||
// if (q1servers)
|
||||
{
|
||||
Master_AddMaster("192.246.40.37:27000", MT_MASTERQW, "id Limbo");
|
||||
Master_AddMaster("192.246.40.37:27002", MT_MASTERQW, "id CTF");
|
||||
Master_AddMaster("192.246.40.37:27003", MT_MASTERQW, "id TeamFortress");
|
||||
Master_AddMaster("192.246.40.37:27004", MT_MASTERQW, "id Miscilaneous");
|
||||
Master_AddMaster("192.246.40.37:27006", MT_MASTERQW, "id Deathmatch Only");
|
||||
Master_AddMaster("150.254.66.120:27000", MT_MASTERQW, "Poland's master server.");
|
||||
Master_AddMaster("62.112.145.129:27000", MT_MASTERQW, "Ocrana master server.");
|
||||
}
|
||||
|
||||
// if (q2servers)
|
||||
{
|
||||
Master_AddMaster("192.246.40.37:27900", MT_MASTERQ2, "id q2 Master.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (mast = master; mast; mast=mast->next)
|
||||
{
|
||||
MasterInfo_Request(mast);
|
||||
}
|
||||
}
|
||||
|
||||
void Master_QueryServer(serverinfo_t *server)
|
||||
{
|
||||
char data[2048];
|
||||
server->sends++;
|
||||
server->refreshtime = Sys_DoubleTime();
|
||||
sprintf(data, "%c%c%c%cstatus", 255, 255, 255, 255);
|
||||
NET_SendPollPacket (strlen(data), data, server->adr);
|
||||
}
|
||||
//send a packet to each server in sequence.
|
||||
void CL_QueryServers(void)
|
||||
{
|
||||
static int poll;
|
||||
int op;
|
||||
serverinfo_t *server;
|
||||
op = poll;
|
||||
|
||||
|
||||
for (server = firstserver; op>0 && server; server=server->next, op--);
|
||||
|
||||
if (!server)
|
||||
{
|
||||
poll = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (op == 0)
|
||||
{
|
||||
if (server->sends < 1)
|
||||
{
|
||||
Master_QueryServer(server);
|
||||
}
|
||||
poll++;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
poll = 0;
|
||||
}
|
||||
|
||||
int Master_TotalCount(void)
|
||||
{
|
||||
int count=0;
|
||||
serverinfo_t *info;
|
||||
|
||||
for (info = firstserver; info; info = info->next)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//true if server is on a different master's list.
|
||||
serverinfo_t *Master_InfoForServer (netadr_t addr)
|
||||
{
|
||||
serverinfo_t *info;
|
||||
|
||||
for (info = firstserver; info; info = info->next)
|
||||
{
|
||||
if (NET_CompareAdr(info->adr, addr))
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
serverinfo_t *Master_InfoForNum (int num)
|
||||
{
|
||||
serverinfo_t *info;
|
||||
|
||||
for (info = firstserver; info; info = info->next)
|
||||
{
|
||||
if (num-- <=0)
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MasterInfo_RemovePlayers(netadr_t adr)
|
||||
{
|
||||
player_t *p, *prev;
|
||||
prev = NULL;
|
||||
for (p = mplayers; p; )
|
||||
{
|
||||
if (NET_CompareAdr(p->adr, adr))
|
||||
{
|
||||
if (prev)
|
||||
prev->next = p->next;
|
||||
else
|
||||
mplayers = p->next;
|
||||
Z_Free(p);
|
||||
p=prev;
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
prev = p;
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
void MasterInfo_AddPlayer(netadr_t serveradr, char *name, int ping, int frags, int colours, char *skin)
|
||||
{
|
||||
player_t *p;
|
||||
p = Z_Malloc(sizeof(player_t));
|
||||
p->next = mplayers;
|
||||
p->adr = serveradr;
|
||||
p->colour = colours;
|
||||
p->frags = frags;
|
||||
Q_strncpyz(p->name, name, sizeof(p->name));
|
||||
Q_strncpyz(p->skin, skin, sizeof(p->skin));
|
||||
mplayers = p;
|
||||
}
|
||||
|
||||
//we got told about a server, parse it's info
|
||||
int CL_ReadServerInfo(char *msg, int servertype, qboolean favorite)
|
||||
{
|
||||
serverdetailedinfo_t details;
|
||||
|
||||
char *token;
|
||||
char *nl;
|
||||
char *name;
|
||||
int ping;
|
||||
int len;
|
||||
serverinfo_t *info;
|
||||
|
||||
info = Master_InfoForServer(net_from);
|
||||
|
||||
if (!info) //not found...
|
||||
{
|
||||
info = Z_Malloc(sizeof(serverinfo_t));
|
||||
|
||||
info->adr = net_from;
|
||||
|
||||
sprintf(info->name, "%s", NET_AdrToString(info->adr));
|
||||
|
||||
info->next = firstserver;
|
||||
firstserver = info;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
MasterInfo_RemovePlayers(info->adr);
|
||||
}
|
||||
|
||||
nl = strchr(msg, '\n');
|
||||
if (nl)
|
||||
{
|
||||
*nl = '\0';
|
||||
nl++;
|
||||
}
|
||||
name = Info_ValueForKey(msg, "hostname");
|
||||
Q_strncpyz(info->name, name, sizeof(info->name));
|
||||
info->special = info->special & (SS_FAVORITE | SS_KEEPINFO); //favorite is never cleared
|
||||
if (!strcmp("FTE", Info_ValueForKey(msg, "*distrib")))
|
||||
info->special |= SS_FTESERVER;
|
||||
else if (!strncmp("FTE", Info_ValueForKey(msg, "*version"), 3))
|
||||
info->special |= SS_FTESERVER;
|
||||
|
||||
|
||||
if (servertype == MT_SINGLEQ2)
|
||||
info->special |= SS_QUAKE2;
|
||||
else if (servertype == MT_SINGLENQ)
|
||||
info->special |= SS_NETQUAKE;
|
||||
if (favorite) //was specifically named, not retrieved from a master.
|
||||
info->special |= SS_FAVORITE;
|
||||
|
||||
ping = (Sys_DoubleTime() - info->refreshtime)*1000;
|
||||
if (ping > 0xffff)
|
||||
info->ping = 0xffff;
|
||||
else
|
||||
info->ping = ping;
|
||||
|
||||
info->players = 0;
|
||||
info->maxplayers = atoi(Info_ValueForKey(msg, "maxclients"));
|
||||
|
||||
info->tl = atoi(Info_ValueForKey(msg, "timelimit"));
|
||||
info->fl = atoi(Info_ValueForKey(msg, "fraglimit"));
|
||||
|
||||
if (servertype == MT_SINGLEQ2)
|
||||
{
|
||||
Q_strncpyz(info->gamedir, Info_ValueForKey(msg, "gamename"), sizeof(info->gamedir));
|
||||
Q_strncpyz(info->map, Info_ValueForKey(msg, "mapname"), sizeof(info->map));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncpyz(info->gamedir, Info_ValueForKey(msg, "*gamedir"), sizeof(info->gamedir));
|
||||
Q_strncpyz(info->map, Info_ValueForKey(msg, "map"), sizeof(info->map));
|
||||
}
|
||||
|
||||
{
|
||||
int clnum;
|
||||
strcpy(details.info, msg);
|
||||
msg = msg+strlen(msg)+1;
|
||||
|
||||
info->players=details.numplayers = 0;
|
||||
for (clnum=0; clnum < MAX_CLIENTS; clnum++)
|
||||
{
|
||||
nl = strchr(msg, '\n');
|
||||
if (!nl)
|
||||
break;
|
||||
*nl = '\0';
|
||||
|
||||
token = msg;
|
||||
if (!token)
|
||||
break;
|
||||
details.players[clnum].userid = atoi(token);
|
||||
token = strchr(token+1, ' ');
|
||||
if (!token)
|
||||
break;
|
||||
details.players[clnum].frags = atoi(token);
|
||||
token = strchr(token+1, ' ');
|
||||
if (!token)
|
||||
break;
|
||||
details.players[clnum].time = atoi(token);
|
||||
msg = token;
|
||||
token = strchr(msg+1, ' ');
|
||||
if (!token) //probably q2 response
|
||||
{
|
||||
//see if this is actually a Quake2 server.
|
||||
token = strchr(msg+1, '\"');
|
||||
if (!token) //it wasn't.
|
||||
break;
|
||||
|
||||
details.players[clnum].ping = details.players[clnum].frags;
|
||||
details.players[clnum].frags = details.players[clnum].userid;
|
||||
|
||||
msg = strchr(token+1, '\"');
|
||||
if (!msg)
|
||||
break;
|
||||
len = msg - token;
|
||||
if (len >= sizeof(details.players[clnum].name))
|
||||
len = sizeof(details.players[clnum].name);
|
||||
Q_strncpyz(details.players[clnum].name, token+1, len);
|
||||
|
||||
details.players[clnum].skin[0] = '\0';
|
||||
|
||||
details.players[clnum].topc = 0;
|
||||
details.players[clnum].botc = 0;
|
||||
details.players[clnum].time = 0;
|
||||
}
|
||||
else //qw responce
|
||||
{
|
||||
details.players[clnum].time = atoi(token);
|
||||
msg = token;
|
||||
token = strchr(msg+1, ' ');
|
||||
if (!token)
|
||||
break;
|
||||
|
||||
details.players[clnum].ping = atoi(token);
|
||||
|
||||
token = strchr(token+1, '\"');
|
||||
if (!token)
|
||||
break;
|
||||
msg = strchr(token+1, '\"');
|
||||
if (!msg)
|
||||
break;
|
||||
len = msg - token;
|
||||
if (len >= sizeof(details.players[clnum].name))
|
||||
len = sizeof(details.players[clnum].name);
|
||||
Q_strncpyz(details.players[clnum].name, token+1, len);
|
||||
details.players[clnum].name[len] = '\0';
|
||||
|
||||
token = strchr(msg+1, '\"');
|
||||
if (!token)
|
||||
break;
|
||||
msg = strchr(token+1, '\"');
|
||||
if (!msg)
|
||||
break;
|
||||
len = msg - token;
|
||||
if (len >= sizeof(details.players[clnum].skin))
|
||||
len = sizeof(details.players[clnum].skin);
|
||||
Q_strncpyz(details.players[clnum].skin, token+1, len);
|
||||
details.players[clnum].skin[len] = '\0';
|
||||
|
||||
token = strchr(msg+1, ' ');
|
||||
if (!token)
|
||||
break;
|
||||
details.players[clnum].topc = atoi(token);
|
||||
token = strchr(token+1, ' ');
|
||||
if (!token)
|
||||
break;
|
||||
details.players[clnum].botc = atoi(token);
|
||||
}
|
||||
|
||||
MasterInfo_AddPlayer(info->adr, details.players[clnum].name, details.players[clnum].ping, details.players[clnum].frags, details.players[clnum].topc*4 | details.players[clnum].botc, details.players[clnum].skin);
|
||||
|
||||
info->players = ++details.numplayers;
|
||||
|
||||
msg = nl;
|
||||
if (!msg)
|
||||
break; //erm...
|
||||
msg++;
|
||||
}
|
||||
}
|
||||
if (!info->moreinfo && ((slist_cacheinfo.value == 2 || NET_CompareAdr(info->adr, selectedserver.adr)) || (info->special & SS_KEEPINFO)))
|
||||
info->moreinfo = Z_Malloc(sizeof(serverdetailedinfo_t));
|
||||
if (NET_CompareAdr(info->adr, selectedserver.adr))
|
||||
selectedserver.detail = info->moreinfo;
|
||||
|
||||
if (info->moreinfo)
|
||||
memcpy(info->moreinfo, &details, sizeof(serverdetailedinfo_t));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//rewrite to scan for existing server instead of wiping all.
|
||||
void CL_MasterListParse(qboolean isq2)
|
||||
{
|
||||
serverinfo_t *info;
|
||||
serverinfo_t *last, *old;
|
||||
|
||||
int p1, p2;
|
||||
MSG_ReadByte ();
|
||||
|
||||
last = firstserver;
|
||||
|
||||
while(msg_readcount+1 < net_message.cursize)
|
||||
{
|
||||
info = Z_Malloc(sizeof(serverinfo_t));
|
||||
info->adr.type = NA_IP;
|
||||
info->adr.ip[0] = MSG_ReadByte();
|
||||
info->adr.ip[1] = MSG_ReadByte();
|
||||
info->adr.ip[2] = MSG_ReadByte();
|
||||
info->adr.ip[3] = MSG_ReadByte();
|
||||
|
||||
p1 = MSG_ReadByte();
|
||||
p2 = MSG_ReadByte();
|
||||
info->adr.port = (int)((short)(p1 + (p2<<8)));
|
||||
if ((old = Master_InfoForServer(info->adr))) //remove if the server already exists.
|
||||
{
|
||||
old->sends = 0; //reset.
|
||||
Z_Free(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
info->special = isq2?SS_QUAKE2:0;
|
||||
info->refreshtime = 0;
|
||||
|
||||
sprintf(info->name, "%s", NET_AdrToString(info->adr));
|
||||
|
||||
info->next = last;
|
||||
last = info;
|
||||
}
|
||||
}
|
||||
|
||||
firstserver = last;
|
||||
}
|
||||
|
||||
#endif
|
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
{-0.525731, 0.000000, 0.850651},
|
||||
{-0.442863, 0.238856, 0.864188},
|
||||
{-0.295242, 0.000000, 0.955423},
|
||||
{-0.309017, 0.500000, 0.809017},
|
||||
{-0.162460, 0.262866, 0.951056},
|
||||
{0.000000, 0.000000, 1.000000},
|
||||
{0.000000, 0.850651, 0.525731},
|
||||
{-0.147621, 0.716567, 0.681718},
|
||||
{0.147621, 0.716567, 0.681718},
|
||||
{0.000000, 0.525731, 0.850651},
|
||||
{0.309017, 0.500000, 0.809017},
|
||||
{0.525731, 0.000000, 0.850651},
|
||||
{0.295242, 0.000000, 0.955423},
|
||||
{0.442863, 0.238856, 0.864188},
|
||||
{0.162460, 0.262866, 0.951056},
|
||||
{-0.681718, 0.147621, 0.716567},
|
||||
{-0.809017, 0.309017, 0.500000},
|
||||
{-0.587785, 0.425325, 0.688191},
|
||||
{-0.850651, 0.525731, 0.000000},
|
||||
{-0.864188, 0.442863, 0.238856},
|
||||
{-0.716567, 0.681718, 0.147621},
|
||||
{-0.688191, 0.587785, 0.425325},
|
||||
{-0.500000, 0.809017, 0.309017},
|
||||
{-0.238856, 0.864188, 0.442863},
|
||||
{-0.425325, 0.688191, 0.587785},
|
||||
{-0.716567, 0.681718, -0.147621},
|
||||
{-0.500000, 0.809017, -0.309017},
|
||||
{-0.525731, 0.850651, 0.000000},
|
||||
{0.000000, 0.850651, -0.525731},
|
||||
{-0.238856, 0.864188, -0.442863},
|
||||
{0.000000, 0.955423, -0.295242},
|
||||
{-0.262866, 0.951056, -0.162460},
|
||||
{0.000000, 1.000000, 0.000000},
|
||||
{0.000000, 0.955423, 0.295242},
|
||||
{-0.262866, 0.951056, 0.162460},
|
||||
{0.238856, 0.864188, 0.442863},
|
||||
{0.262866, 0.951056, 0.162460},
|
||||
{0.500000, 0.809017, 0.309017},
|
||||
{0.238856, 0.864188, -0.442863},
|
||||
{0.262866, 0.951056, -0.162460},
|
||||
{0.500000, 0.809017, -0.309017},
|
||||
{0.850651, 0.525731, 0.000000},
|
||||
{0.716567, 0.681718, 0.147621},
|
||||
{0.716567, 0.681718, -0.147621},
|
||||
{0.525731, 0.850651, 0.000000},
|
||||
{0.425325, 0.688191, 0.587785},
|
||||
{0.864188, 0.442863, 0.238856},
|
||||
{0.688191, 0.587785, 0.425325},
|
||||
{0.809017, 0.309017, 0.500000},
|
||||
{0.681718, 0.147621, 0.716567},
|
||||
{0.587785, 0.425325, 0.688191},
|
||||
{0.955423, 0.295242, 0.000000},
|
||||
{1.000000, 0.000000, 0.000000},
|
||||
{0.951056, 0.162460, 0.262866},
|
||||
{0.850651, -0.525731, 0.000000},
|
||||
{0.955423, -0.295242, 0.000000},
|
||||
{0.864188, -0.442863, 0.238856},
|
||||
{0.951056, -0.162460, 0.262866},
|
||||
{0.809017, -0.309017, 0.500000},
|
||||
{0.681718, -0.147621, 0.716567},
|
||||
{0.850651, 0.000000, 0.525731},
|
||||
{0.864188, 0.442863, -0.238856},
|
||||
{0.809017, 0.309017, -0.500000},
|
||||
{0.951056, 0.162460, -0.262866},
|
||||
{0.525731, 0.000000, -0.850651},
|
||||
{0.681718, 0.147621, -0.716567},
|
||||
{0.681718, -0.147621, -0.716567},
|
||||
{0.850651, 0.000000, -0.525731},
|
||||
{0.809017, -0.309017, -0.500000},
|
||||
{0.864188, -0.442863, -0.238856},
|
||||
{0.951056, -0.162460, -0.262866},
|
||||
{0.147621, 0.716567, -0.681718},
|
||||
{0.309017, 0.500000, -0.809017},
|
||||
{0.425325, 0.688191, -0.587785},
|
||||
{0.442863, 0.238856, -0.864188},
|
||||
{0.587785, 0.425325, -0.688191},
|
||||
{0.688191, 0.587785, -0.425325},
|
||||
{-0.147621, 0.716567, -0.681718},
|
||||
{-0.309017, 0.500000, -0.809017},
|
||||
{0.000000, 0.525731, -0.850651},
|
||||
{-0.525731, 0.000000, -0.850651},
|
||||
{-0.442863, 0.238856, -0.864188},
|
||||
{-0.295242, 0.000000, -0.955423},
|
||||
{-0.162460, 0.262866, -0.951056},
|
||||
{0.000000, 0.000000, -1.000000},
|
||||
{0.295242, 0.000000, -0.955423},
|
||||
{0.162460, 0.262866, -0.951056},
|
||||
{-0.442863, -0.238856, -0.864188},
|
||||
{-0.309017, -0.500000, -0.809017},
|
||||
{-0.162460, -0.262866, -0.951056},
|
||||
{0.000000, -0.850651, -0.525731},
|
||||
{-0.147621, -0.716567, -0.681718},
|
||||
{0.147621, -0.716567, -0.681718},
|
||||
{0.000000, -0.525731, -0.850651},
|
||||
{0.309017, -0.500000, -0.809017},
|
||||
{0.442863, -0.238856, -0.864188},
|
||||
{0.162460, -0.262866, -0.951056},
|
||||
{0.238856, -0.864188, -0.442863},
|
||||
{0.500000, -0.809017, -0.309017},
|
||||
{0.425325, -0.688191, -0.587785},
|
||||
{0.716567, -0.681718, -0.147621},
|
||||
{0.688191, -0.587785, -0.425325},
|
||||
{0.587785, -0.425325, -0.688191},
|
||||
{0.000000, -0.955423, -0.295242},
|
||||
{0.000000, -1.000000, 0.000000},
|
||||
{0.262866, -0.951056, -0.162460},
|
||||
{0.000000, -0.850651, 0.525731},
|
||||
{0.000000, -0.955423, 0.295242},
|
||||
{0.238856, -0.864188, 0.442863},
|
||||
{0.262866, -0.951056, 0.162460},
|
||||
{0.500000, -0.809017, 0.309017},
|
||||
{0.716567, -0.681718, 0.147621},
|
||||
{0.525731, -0.850651, 0.000000},
|
||||
{-0.238856, -0.864188, -0.442863},
|
||||
{-0.500000, -0.809017, -0.309017},
|
||||
{-0.262866, -0.951056, -0.162460},
|
||||
{-0.850651, -0.525731, 0.000000},
|
||||
{-0.716567, -0.681718, -0.147621},
|
||||
{-0.716567, -0.681718, 0.147621},
|
||||
{-0.525731, -0.850651, 0.000000},
|
||||
{-0.500000, -0.809017, 0.309017},
|
||||
{-0.238856, -0.864188, 0.442863},
|
||||
{-0.262866, -0.951056, 0.162460},
|
||||
{-0.864188, -0.442863, 0.238856},
|
||||
{-0.809017, -0.309017, 0.500000},
|
||||
{-0.688191, -0.587785, 0.425325},
|
||||
{-0.681718, -0.147621, 0.716567},
|
||||
{-0.442863, -0.238856, 0.864188},
|
||||
{-0.587785, -0.425325, 0.688191},
|
||||
{-0.309017, -0.500000, 0.809017},
|
||||
{-0.147621, -0.716567, 0.681718},
|
||||
{-0.425325, -0.688191, 0.587785},
|
||||
{-0.162460, -0.262866, 0.951056},
|
||||
{0.442863, -0.238856, 0.864188},
|
||||
{0.162460, -0.262866, 0.951056},
|
||||
{0.309017, -0.500000, 0.809017},
|
||||
{0.147621, -0.716567, 0.681718},
|
||||
{0.000000, -0.525731, 0.850651},
|
||||
{0.425325, -0.688191, 0.587785},
|
||||
{0.587785, -0.425325, 0.688191},
|
||||
{0.688191, -0.587785, 0.425325},
|
||||
{-0.955423, 0.295242, 0.000000},
|
||||
{-0.951056, 0.162460, 0.262866},
|
||||
{-1.000000, 0.000000, 0.000000},
|
||||
{-0.850651, 0.000000, 0.525731},
|
||||
{-0.955423, -0.295242, 0.000000},
|
||||
{-0.951056, -0.162460, 0.262866},
|
||||
{-0.864188, 0.442863, -0.238856},
|
||||
{-0.951056, 0.162460, -0.262866},
|
||||
{-0.809017, 0.309017, -0.500000},
|
||||
{-0.864188, -0.442863, -0.238856},
|
||||
{-0.951056, -0.162460, -0.262866},
|
||||
{-0.809017, -0.309017, -0.500000},
|
||||
{-0.681718, 0.147621, -0.716567},
|
||||
{-0.681718, -0.147621, -0.716567},
|
||||
{-0.850651, 0.000000, -0.525731},
|
||||
{-0.688191, 0.587785, -0.425325},
|
||||
{-0.587785, 0.425325, -0.688191},
|
||||
{-0.425325, 0.688191, -0.587785},
|
||||
{-0.425325, -0.688191, -0.587785},
|
||||
{-0.587785, -0.425325, -0.688191},
|
||||
{-0.688191, -0.587785, -0.425325},
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// quakedef.h -- primary header for client
|
||||
|
||||
|
||||
|
||||
#if _MSC_VER
|
||||
#define MSVCDISABLEWARNINGS
|
||||
#endif
|
||||
|
||||
#ifdef MSVCDISABLEWARNINGS
|
||||
//#pragma warning( disable : 4244 4127 4201 4214 4514 4305 4115 4018)
|
||||
/*#pragma warning( disable : 4244) //conversion from const double to float
|
||||
#pragma warning( disable : 4305) //truncation from const double to float
|
||||
#pragma warning( disable : 4018) //signed/unsigned mismatch... fix these?
|
||||
#pragma warning( disable : 4706) //assignment within conditional expression - watch for these in GCC where they can be fixed but still functional.
|
||||
#pragma warning( disable : 4100) //unreferenced formal parameter
|
||||
#pragma warning( disable : 4201) //nonstandard extension used : nameless struct/union
|
||||
#pragma warning( disable : 4213) //nonstandard extension used : cast on l-value
|
||||
#pragma warning( disable : 4127) //conditional expression is constant - fixme?
|
||||
*/
|
||||
#pragma warning( 4 : 4244) //conversion from const double to float
|
||||
#pragma warning( 4 : 4305) //truncation from const double to float
|
||||
#pragma warning( 4 : 4018) //truncation from const double to float
|
||||
|
||||
#pragma warning( 2 : 4701)
|
||||
#pragma warning(2:4132 4268)// const object not initialized
|
||||
|
||||
#pragma warning(2:4032) // function arg has different type from declaration
|
||||
#pragma warning(2:4092) // 'sizeof' value too big
|
||||
#pragma warning(2:4132 4268)// const object not initialized
|
||||
//#pragma warning(2:4152) // pointer conversion between function and data
|
||||
#pragma warning(2:4239) // standard doesn't allow this conversion
|
||||
#pragma warning(2:4701) // local variable used without being initialized
|
||||
//#pragma warning(2:4706) // if (a=b) instead of (if a==b)
|
||||
#pragma warning(2:4709) // comma in array subscript
|
||||
#pragma warning(3:4061) // not all enum values tested in switch statement
|
||||
#pragma warning(3:4710) // inline function was not inlined
|
||||
#pragma warning(3:4121) // space added for structure alignment
|
||||
#pragma warning(3:4505) // unreferenced local function removed
|
||||
#pragma warning(3:4019) // empty statement at global scope
|
||||
//#pragma warning(3:4057) // pointers refer to different base types
|
||||
#pragma warning(3:4125) // decimal digit terminates octal escape
|
||||
//#pragma warning(2:4131) // old-style function declarator
|
||||
#pragma warning(3:4211) // extern redefined as static
|
||||
//#pragma warning(3:4213) // cast on left side of = is non-standard
|
||||
#pragma warning(3:4222) // member function at file scope shouldn't be static
|
||||
#pragma warning(3:4234 4235)// keyword not supported or reserved for future
|
||||
#pragma warning(3:4504) // type ambiguous; simplify code
|
||||
#pragma warning(3:4507) // explicit linkage specified after default linkage
|
||||
#pragma warning(3:4515) // namespace uses itself
|
||||
#pragma warning(3:4516 4517)// access declarations are deprecated
|
||||
#pragma warning(3:4670) // base class of thrown object is inaccessible
|
||||
#pragma warning(3:4671) // copy ctor of thrown object is inaccessible
|
||||
#pragma warning(3:4673) // thrown object cannot be handled in catch block
|
||||
#pragma warning(3:4674) // dtor of thrown object is inaccessible
|
||||
#pragma warning(3:4705) // statement has no effect (example: a+1;)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define QUAKEDEF_H__
|
||||
|
||||
#define WATERLAYERS
|
||||
|
||||
#ifdef GLQUAKE
|
||||
#define RGLQUAKE
|
||||
#undef GLQUAKE //compiler option
|
||||
#endif
|
||||
|
||||
#ifdef CLIENTONLY
|
||||
#define isDedicated true
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#define PNG_SUCKS_WITH_SETJMP //cos it does.
|
||||
#endif
|
||||
|
||||
#define QUAKE_GAME // as opposed to utilities
|
||||
//define PARANOID // speed sapping error checking
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "bothdefs.h" //we need to know if png is available
|
||||
#if defined(AVAIL_PNGLIB) && defined(PNG_SUCKS_WITH_SETJMP)
|
||||
#include <png.h>
|
||||
#else
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "translate.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "bspfile.h"
|
||||
#include "vid.h"
|
||||
#include "sys.h"
|
||||
#include "zone.h"
|
||||
#include "mathlib.h"
|
||||
#include "wad.h"
|
||||
#include "cvar.h"
|
||||
#include "screen.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
#include "cmd.h"
|
||||
#include "sbar.h"
|
||||
#include "sound.h"
|
||||
#include "merged.h"
|
||||
#include "render.h"
|
||||
#include "client.h"
|
||||
|
||||
#include "vm.h"
|
||||
|
||||
|
||||
//#if defined(RGLQUAKE)
|
||||
#include "gl_model.h"
|
||||
//#else
|
||||
//#include "model.h"
|
||||
//#endif
|
||||
|
||||
#if defined(SWQUAKE)
|
||||
#include "d_iface.h"
|
||||
#endif
|
||||
|
||||
#ifdef PEXT_BULLETENS
|
||||
#include "r_bulleten.h"
|
||||
#endif
|
||||
|
||||
#include "input.h"
|
||||
#include "keys.h"
|
||||
#include "console.h"
|
||||
#include "view.h"
|
||||
#include "menu.h"
|
||||
#include "crc.h"
|
||||
#include "cdaudio.h"
|
||||
#include "pmove.h"
|
||||
|
||||
#ifndef CLIENTONLY
|
||||
#include "progs.h"
|
||||
#include "world.h"
|
||||
//#ifdef Q2SERVER
|
||||
#include "q2game.h" //under development.
|
||||
//#endif
|
||||
#include "server.h"
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// the host system specifies the base of the directory tree, the
|
||||
// command line parms passed to the program, and the amount of memory
|
||||
// available for the program to use
|
||||
|
||||
typedef struct quakeparms_s
|
||||
{
|
||||
char *basedir;
|
||||
char *cachedir; // for development over ISDN lines
|
||||
int argc;
|
||||
char **argv;
|
||||
void *membase;
|
||||
int memsize;
|
||||
} quakeparms_t;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
#define MAX_NUM_ARGVS 128
|
||||
|
||||
|
||||
extern qboolean noclip_anglehack;
|
||||
|
||||
|
||||
//
|
||||
// host
|
||||
//
|
||||
extern quakeparms_t host_parms;
|
||||
|
||||
extern cvar_t sys_ticrate;
|
||||
extern cvar_t sys_nostdout;
|
||||
extern cvar_t developer;
|
||||
|
||||
extern cvar_t password;
|
||||
|
||||
extern qboolean host_initialized; // true if into command execution
|
||||
extern double host_frametime;
|
||||
extern qbyte *host_basepal;
|
||||
extern qbyte *host_colormap;
|
||||
extern int host_framecount; // incremented every frame, never reset
|
||||
extern double realtime; // not bounded in any way, changed at
|
||||
// start of every frame, never reset
|
||||
|
||||
void Host_ServerFrame (void);
|
||||
void Host_InitCommands (void);
|
||||
void Host_Init (quakeparms_t *parms);
|
||||
void Host_Shutdown(void);
|
||||
void VARGS Host_Error (char *error, ...);
|
||||
void VARGS Host_EndGame (char *message, ...);
|
||||
qboolean Host_SimulationTime(float time);
|
||||
void Host_Frame (float time);
|
||||
void Host_Quit_f (void);
|
||||
void VARGS Host_ClientCommands (char *fmt, ...);
|
||||
void Host_ShutdownServer (qboolean crash);
|
||||
|
||||
extern qboolean msg_suppress_1; // suppresses resolution and cache size console output
|
||||
// an fullscreen DIB focus gain/loss
|
||||
|
||||
|
||||
#if !defined(SERVERONLY) && !defined(CLIENTONLY)
|
||||
extern qboolean isDedicated;
|
||||
#endif
|
||||
|
||||
|
||||
void Validation_IncludeFile(char *filename, char *file, int filelen);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,612 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_bulleten.c
|
||||
//
|
||||
//draws new stuff onto the mip each frame!
|
||||
//text set each frame
|
||||
|
||||
#include "quakedef.h"
|
||||
#ifdef PEXT_BULLETENS
|
||||
|
||||
#ifdef SWQUAKE
|
||||
#include "r_local.h"
|
||||
#include "d_local.h"
|
||||
#endif
|
||||
#include "glquake.h"//hack
|
||||
|
||||
/*
|
||||
Effects:
|
||||
0: standard plain background
|
||||
1: normal texture + scrolling text
|
||||
2: Sparkling
|
||||
3: Simply a scrolling texture
|
||||
4: Ripples (for water) - it is treated as a bulleten, because that way, we can easily hook into it. There is never any text though.
|
||||
5:
|
||||
6:
|
||||
7:
|
||||
8:
|
||||
9:
|
||||
*/
|
||||
|
||||
cvar_t bul_text1 = {"bul_text1", "0Cheesy Forethoug\\nht entertainment"};
|
||||
cvar_t bul_text2 = {"bul_text2", "2"};
|
||||
cvar_t bul_text3 = {"bul_text3", "0Join Shubs Army\\nFight for Fear"};
|
||||
cvar_t bul_text4 = {"bul_text4", "0Need a gun?\\nGoto bobs place!"};
|
||||
cvar_t bul_text5 = {"bul_text5", "0Beware the fans\\nThey can hurt."};
|
||||
cvar_t bul_text6 = {"bul_text6", "2Quake B\\n Arena "};
|
||||
|
||||
cvar_t bul_scrollspeedx = {"bul_scrollspeedx", "-20"}; //pixels per second
|
||||
cvar_t bul_scrollspeedy = {"bul_scrollspeedy", "-10"}; //pixels per second
|
||||
cvar_t bul_backcol = {"bul_backcolour", "1"};
|
||||
cvar_t bul_textpalette = {"bul_textpalette", "0"};
|
||||
cvar_t bul_norender = {"bul_norender", "0"};
|
||||
cvar_t bul_sparkle = {"bul_sparkle", "7"};
|
||||
cvar_t bul_forcemode = {"bul_forcemode", "-1"};
|
||||
cvar_t bul_ripplespeed = {"bul_ripplespeed", "32"};
|
||||
cvar_t bul_rippleamount = {"bul_rippleamount", "2"};
|
||||
cvar_t bul_nowater = {"bul_nowater", "1"};
|
||||
|
||||
int bultextpallete = 0;
|
||||
|
||||
bulletentexture_t *bulletentexture;
|
||||
|
||||
int nlstrlen(char *str, int *lines) //strlen, but for longest line in string
|
||||
{
|
||||
int cl = 0, ol = 0;
|
||||
|
||||
if (*str >= '0' && *str <= '9') //used to set an effect
|
||||
str++;
|
||||
|
||||
*lines = 1;
|
||||
for (;*str;str++,cl++)
|
||||
{
|
||||
if (*str == '\\')
|
||||
{
|
||||
str++;
|
||||
if (*str == 'n')
|
||||
{
|
||||
if (ol < cl)
|
||||
ol = cl;
|
||||
cl = 0;
|
||||
*lines += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cl > ol)
|
||||
return cl;
|
||||
return ol;
|
||||
}
|
||||
|
||||
void WipeBulletenTextures(void)
|
||||
{
|
||||
bulletentexture_t *a;
|
||||
// return;
|
||||
for (a = bulletentexture; a; a=a->next)
|
||||
{
|
||||
a->texture = NULL;
|
||||
}
|
||||
bulletentexture = NULL;
|
||||
}
|
||||
|
||||
qboolean R_AddBulleten (texture_t *textur)
|
||||
{
|
||||
bulletentexture_t *a;
|
||||
int len;
|
||||
int lines;
|
||||
|
||||
int type;
|
||||
char *text="";
|
||||
#ifndef CLIENTONLY
|
||||
if (isDedicated)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (!Q_strncmp(textur->name,"b_lead",6))
|
||||
{
|
||||
type = 0; // name winner
|
||||
text = bul_text1.string;
|
||||
}
|
||||
else if (!Q_strncmp(textur->name,"b_loose",7))
|
||||
{
|
||||
type = 1; // name looser
|
||||
text = bul_text2.string;
|
||||
}
|
||||
else if (!Q_strncmp(textur->name, "b_text\0",7))
|
||||
{
|
||||
type = 2 + rand() % 6; //random advert (all of these end up the same (first found))
|
||||
// ;
|
||||
}
|
||||
else if (!Q_strncmp(textur->name, "b_text_1",8))
|
||||
{
|
||||
type = 2; // advert 1
|
||||
text = bul_text1.string;
|
||||
}
|
||||
else if (!Q_strncmp(textur->name, "b_text_2", 8))
|
||||
{
|
||||
type = 3; // advert 2
|
||||
text = bul_text2.string;
|
||||
}
|
||||
else if (!Q_strncmp(textur->name, "b_text_3", 8))
|
||||
{
|
||||
type = 4; // advert 3
|
||||
text = bul_text3.string;
|
||||
}
|
||||
else if (!Q_strncmp(textur->name, "b_text_4", 8))
|
||||
{
|
||||
type = 5; // advert 4
|
||||
text = bul_text4.string;
|
||||
}
|
||||
else if (!Q_strncmp(textur->name, "b_text_5", 8))
|
||||
{
|
||||
type = 6;
|
||||
text = bul_text5.string;
|
||||
}
|
||||
else if (!Q_strncmp(textur->name, "b_text_6", 8))
|
||||
{
|
||||
type = 7;
|
||||
text = bul_text6.string;
|
||||
}
|
||||
// water ripples
|
||||
else if (!Q_strncmp(textur->name,"*", 1) && !bul_nowater.value)
|
||||
{
|
||||
type = -1;
|
||||
text = "";
|
||||
}
|
||||
|
||||
else if (!Q_strncmp(textur->name,"bul_", 4))
|
||||
{
|
||||
type = atoi(textur->name+4);
|
||||
text = "";
|
||||
}
|
||||
else // not a bulleten
|
||||
return false;
|
||||
|
||||
|
||||
for (a = bulletentexture; a; a=a->next)
|
||||
{
|
||||
if (a->texture == textur)
|
||||
return true; //texture address already used
|
||||
}
|
||||
if (a == NULL)
|
||||
{ //not found it, create a new texture
|
||||
a = Hunk_AllocName(sizeof(struct bulletentexture_s) + ((textur->width) * (textur->height)), "bulleten");
|
||||
a->next = bulletentexture; //add in first
|
||||
bulletentexture = a;
|
||||
|
||||
len = nlstrlen(text, &lines);
|
||||
a->texture = textur;
|
||||
a->bultextleft = (a->texture->width - (len*8)) / 2;
|
||||
a->bultexttop = (a->texture->height - (lines*8)) / 2;
|
||||
a->type = type;
|
||||
a->normaltexture = (qbyte *) a + sizeof(struct bulletentexture_s);
|
||||
memcpy(a->normaltexture, (qbyte *) textur + textur->offsets[0], textur->width * textur->height);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//user wants to force a world texture into a bulleten board.
|
||||
void R_BulletenForce_f (void)
|
||||
{
|
||||
extern model_t mod_known[];
|
||||
extern int mod_numknown;
|
||||
|
||||
model_t *mod;
|
||||
texture_t *tx;
|
||||
char *match = Cmd_Argv(1);
|
||||
|
||||
int i, m, s;
|
||||
|
||||
|
||||
for (m=0 , mod=mod_known ; m<mod_numknown ; m++, mod++)
|
||||
{
|
||||
if (mod->type == mod_brush && !mod->needload)
|
||||
{
|
||||
for (i = 0; i < mod->numtextures; i++)
|
||||
{
|
||||
tx = mod->textures[i];
|
||||
if (!tx)
|
||||
continue; //happens on e1m2
|
||||
|
||||
if (!stricmp(tx->name, match))
|
||||
{
|
||||
char *text = "";
|
||||
int len, lines;
|
||||
bulletentexture_t *a;
|
||||
|
||||
for (a = bulletentexture; a; a=a->next)
|
||||
{
|
||||
if (a->texture == tx)
|
||||
{
|
||||
a->type = atoi(Cmd_Argv(2));
|
||||
break; //texture address already used
|
||||
}
|
||||
}
|
||||
if (a == NULL)
|
||||
{ //not found it, create a new texture
|
||||
a = Hunk_AllocName(sizeof(struct bulletentexture_s) + ((tx->width) * (tx->height)), "bulleten");
|
||||
a->next = bulletentexture; //add in first
|
||||
bulletentexture = a;
|
||||
|
||||
len = nlstrlen(text, &lines);
|
||||
a->texture = tx;
|
||||
a->bultextleft = (a->texture->width - (len*8)) / 2;
|
||||
a->bultexttop = (a->texture->height - (lines*8)) / 2;
|
||||
a->type = atoi(Cmd_Argv(2));
|
||||
a->normaltexture = (qbyte *) a + sizeof(struct bulletentexture_s);
|
||||
memcpy(a->normaltexture, (qbyte *) tx + tx->offsets[0], tx->width * tx->height);
|
||||
|
||||
for (s = 0; s < mod->numsurfaces; s++)
|
||||
{
|
||||
mod->surfaces[s].flags |= SURF_BULLETEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void R_SetupBulleten (void)
|
||||
{
|
||||
bulletentexture_t *a;
|
||||
int len;
|
||||
int lines;
|
||||
player_info_t *s;
|
||||
char text[256];
|
||||
|
||||
if (bul_norender.value || cl.paused) //don't scroll when paused
|
||||
return;
|
||||
|
||||
bultextpallete = bul_textpalette.value * 16;
|
||||
|
||||
if (bultextpallete < 0) //not the negatives
|
||||
bultextpallete = 0;
|
||||
if (bultextpallete > 255 - vid.fullbright) // don't allow shifting into the fullbrights, (compensate for pallete scale
|
||||
bultextpallete = 0;
|
||||
|
||||
Sbar_SortFrags (false); //find who's winning and who's loosing
|
||||
|
||||
for (a = bulletentexture; a; a=a->next)
|
||||
{
|
||||
if (a->texture != NULL)
|
||||
{
|
||||
switch (a->type)
|
||||
{
|
||||
case -1:
|
||||
sprintf(text, "4"); //negative values have no text
|
||||
break;
|
||||
|
||||
case 0: //leader
|
||||
s = &cl.players[fragsort[0]];
|
||||
if (!s->name[0])
|
||||
{
|
||||
sprintf(text, "0%s", bul_text1.string);
|
||||
break;
|
||||
}
|
||||
if (s->frags == 1)
|
||||
sprintf(text, "0%s is leading\nwith 1 frag!", s->name);
|
||||
else
|
||||
sprintf(text, "0%s is leading\nwith %i frags!", s->name, s->frags);
|
||||
break;
|
||||
|
||||
case 1: //looser
|
||||
s = &cl.players[fragsort[scoreboardlines-1]];
|
||||
if (!s->name[0])
|
||||
{
|
||||
sprintf(text, bul_text2.string);
|
||||
break;
|
||||
}
|
||||
if (s->frags == 1)
|
||||
sprintf(text, "0%s is behind\nwith 1 frag!", s->name);
|
||||
else
|
||||
sprintf(text, "0%s is behind\nwith %i frags!", s->name, s->frags);
|
||||
break;
|
||||
|
||||
case 2: //an add
|
||||
sprintf(text, bul_text1.string);
|
||||
break;
|
||||
|
||||
case 3: //another add
|
||||
sprintf(text, bul_text2.string);
|
||||
break;
|
||||
|
||||
case 4: //yet another add
|
||||
sprintf(text, bul_text3.string);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
sprintf(text, bul_text4.string);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
sprintf(text, bul_text5.string);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
sprintf(text, bul_text6.string);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
*text = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(text, "Unrecognised Bulleten");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
len = nlstrlen(text, &lines);
|
||||
#if 1
|
||||
if (lines*8 <= a->texture->height)
|
||||
a->bultexttop = (a->texture->height - lines*8)/2;
|
||||
else
|
||||
a->bultexttop = ((int)(cl.time * bul_scrollspeedy.value) % (a->texture->height + lines * 8)) - lines * 8;
|
||||
#else
|
||||
if (lines*8 <= a->texture->height)
|
||||
a->bultexttop = (a->texture->height - (lines*8)) / 2;
|
||||
else
|
||||
{
|
||||
a->bultexttop += bul_scrollspeedy.value;
|
||||
if (a->bultexttop < lines * -8)
|
||||
a->bultexttop = (signed int) a->texture->height;
|
||||
if (a->bultexttop > (signed int) a->texture->height)
|
||||
a->bultexttop = lines * -8;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
if (len*8 <= a->texture->width)
|
||||
a->bultextleft = a->texture->width/2 - len*4;
|
||||
else
|
||||
a->bultextleft = ((int)(cl.time * bul_scrollspeedx.value) % (a->texture->width + len * 8)) - len * 8;
|
||||
#else
|
||||
if (len*8 <= a->texture->width)
|
||||
a->bultextleft = (a->texture->width - (len*8)) / 2;
|
||||
else
|
||||
{
|
||||
a->bultextleft += bul_scrollspeedx.value;
|
||||
if (a->bultextleft < len * -8)
|
||||
a->bultextleft = (signed int) a->texture->width;
|
||||
if (a->bultextleft > (signed int) a->texture->width)
|
||||
a->bultextleft = len * -8;
|
||||
}
|
||||
#endif
|
||||
R_MakeBulleten(a->texture, a->bultextleft, a->bultexttop, text, a->normaltexture);
|
||||
|
||||
#ifdef RGLQUAKE
|
||||
if (qrenderer == QR_OPENGL)
|
||||
{
|
||||
GL_Bind(a->texture->gl_texturenum);
|
||||
|
||||
GL_Upload8 ((qbyte *)a->texture + a->texture->offsets[0], a->texture->width, a->texture->height, false, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// PR_SwitchProgs(mainprogs);
|
||||
}
|
||||
|
||||
void Draw_CharToMip (int num, qbyte *mip, int x, int y, int width, int height)
|
||||
{
|
||||
int row, col;
|
||||
qbyte *source;
|
||||
int drawline;
|
||||
int i;
|
||||
|
||||
int s, e;
|
||||
|
||||
s = 0;
|
||||
e = 8;
|
||||
if (x<0)
|
||||
s = s - x;
|
||||
|
||||
if (x > width - e)
|
||||
e = width - x;
|
||||
|
||||
if (s > e)
|
||||
return;
|
||||
if (y >= height)
|
||||
return;
|
||||
if (y < -8)
|
||||
return;
|
||||
if (!draw_chars)
|
||||
return;
|
||||
|
||||
if (y <= 0)
|
||||
mip += x;
|
||||
else
|
||||
mip += (width*y) + x;
|
||||
|
||||
|
||||
row = num>>4;
|
||||
col = num&15;
|
||||
source = draw_chars + (row<<10) + (col<<3);
|
||||
if (y < 0)
|
||||
source -= 128*y;
|
||||
|
||||
drawline = height-y;
|
||||
if (drawline > 8)
|
||||
drawline = 8;
|
||||
|
||||
if (y < 0)
|
||||
drawline += y;
|
||||
|
||||
while (drawline--)
|
||||
{
|
||||
for (i=s ; i<e ; i++)
|
||||
if (source[i] != 255 && source[i])
|
||||
mip[i] = source[i] + bultextpallete;
|
||||
source += 128;
|
||||
mip += width;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Draw_StringToMip(char *str, qbyte *mip, int x, int y, int width, int height)
|
||||
{
|
||||
int nx = x;
|
||||
for (; *str; str++, nx+=8)
|
||||
{
|
||||
if (*str == '\\')
|
||||
{
|
||||
str++;
|
||||
if (!*str)
|
||||
break;
|
||||
|
||||
switch (*str)
|
||||
{
|
||||
case 'n':
|
||||
nx = x-8; // compensate for the 'for' increment
|
||||
y+=8;
|
||||
continue;
|
||||
case '\\':
|
||||
break;
|
||||
default:
|
||||
nx = x-8; // compensate for the 'for' increment
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Draw_CharToMip(*str, mip, nx, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void R_MakeBulleten (texture_t *textur, int lefttext, int toptext, char *text, qbyte *background)
|
||||
{
|
||||
qbyte bc;
|
||||
int x;
|
||||
int y;
|
||||
int effect;
|
||||
int progress;
|
||||
qbyte *mip;
|
||||
|
||||
if (*text >= '0' && *text <= '9')
|
||||
{
|
||||
effect = *text - '0';
|
||||
text++;
|
||||
}
|
||||
else
|
||||
effect = 0;
|
||||
|
||||
if (bul_forcemode.value != -1.0)
|
||||
effect = bul_forcemode.value;
|
||||
|
||||
switch (effect)
|
||||
{
|
||||
default: //solid block colour
|
||||
bc = bul_backcol.value;
|
||||
mip = (qbyte *) textur + textur->offsets[0];
|
||||
Q_memset (mip, bc, textur->width*textur->height);
|
||||
break;
|
||||
|
||||
case 1: //maintain background
|
||||
mip = (qbyte *) textur + textur->offsets[0];
|
||||
memcpy (mip, background, textur->width*textur->height);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
//put in a wierd sparkly effect - interference
|
||||
bc = bul_sparkle.value;
|
||||
mip = (qbyte *) textur + textur->offsets[0];
|
||||
|
||||
for (x=0; x<textur->width*textur->height; x++, mip++)
|
||||
*mip = rand() & bc;
|
||||
|
||||
break;
|
||||
|
||||
case 3: //scrolling mip
|
||||
progress = (int) (realtime*-bul_scrollspeedx.value) % (textur->width);
|
||||
mip = (qbyte *) textur + textur->offsets[0] + progress * textur->height;
|
||||
for (x=0; x<progress; x++, mip++, background++)
|
||||
*mip = *background;
|
||||
|
||||
mip = (qbyte *) textur + textur->offsets[0];
|
||||
for (; x<textur->width*textur->height; x++, mip++, background++)
|
||||
*mip = *background;
|
||||
break;
|
||||
|
||||
case 4: //water distortions
|
||||
mip = (qbyte *) textur + textur->offsets[0];
|
||||
memcpy (mip, background, textur->width*textur->height);
|
||||
|
||||
mip = (qbyte *) textur + textur->offsets[0];
|
||||
for (y = 0; y < textur->height; y++)
|
||||
{
|
||||
for (x = 0; x < textur->width; x++)
|
||||
{
|
||||
progress = *mip & 0x0F;
|
||||
|
||||
/* assume no full brights.
|
||||
if ((*mip & 0xF0) == 0xf0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
*/ if (*mip >= 0x80 && *mip < 0xe0) //backwards ranges
|
||||
progress = progress - (sin(((x+(sin((y/2+cl.time))*3) + (cl.time*bul_ripplespeed.value))/textur->width) * (2 * 3.14))*bul_rippleamount.value);
|
||||
else
|
||||
progress = progress + (sin(((x+(sin((y/2+cl.time))*3) + (cl.time*bul_ripplespeed.value))/textur->width) * (2 * 3.14))*bul_rippleamount.value);
|
||||
|
||||
if (progress > 15)
|
||||
progress = 15;
|
||||
if (progress < 0)
|
||||
progress = 0;
|
||||
|
||||
|
||||
*mip = progress | (*mip & 0xF0);
|
||||
mip++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (*text == '\0')
|
||||
return;
|
||||
|
||||
mip = (qbyte *) textur + textur->offsets[0];
|
||||
|
||||
Draw_StringToMip (text, mip, lefttext, toptext, textur->width, textur->height);
|
||||
}
|
||||
|
||||
|
||||
void Bul_ParseMessage(void)
|
||||
{
|
||||
cvar_t *cv;
|
||||
int num;
|
||||
char *str;
|
||||
num = MSG_ReadByte ();
|
||||
str = MSG_ReadString ();
|
||||
|
||||
switch (num)
|
||||
{
|
||||
default:
|
||||
case 1: cv = &bul_text1; break;
|
||||
case 2: cv = &bul_text2; break;
|
||||
case 3: cv = &bul_text3; break;
|
||||
case 4: cv = &bul_text4; break;
|
||||
case 5: cv = &bul_text5; break;
|
||||
case 6: cv = &bul_text6; break;
|
||||
}
|
||||
Cvar_Set(cv, str);
|
||||
}
|
||||
|
||||
#endif //usebulletens
|
|
@ -0,0 +1,43 @@
|
|||
#define MAXBULLETENS 12 //remove limits
|
||||
|
||||
extern cvar_t bul_advert1;
|
||||
extern cvar_t bul_advert2;
|
||||
extern cvar_t bul_advert3;
|
||||
extern cvar_t bul_advert4;
|
||||
extern cvar_t bul_advertvents;
|
||||
extern cvar_t bul_advertq3;
|
||||
extern cvar_t bul_scrollspeedx;
|
||||
extern cvar_t bul_scrollspeedy;
|
||||
extern cvar_t bul_backcol;
|
||||
extern cvar_t bul_textpalette;
|
||||
extern cvar_t bul_norender;
|
||||
|
||||
|
||||
typedef struct bulletentexture_s
|
||||
{
|
||||
texture_t *texture;
|
||||
int bultextleft;
|
||||
int bultexttop;
|
||||
int type;
|
||||
qbyte *normaltexture;
|
||||
|
||||
struct bulletentexture_s *next;
|
||||
} bulletentexture_t;
|
||||
|
||||
extern bulletentexture_t *bulletentexture;
|
||||
|
||||
extern qbyte *draw_chars; //console text
|
||||
|
||||
|
||||
extern int scoreboardlines;
|
||||
extern int fragsort[];
|
||||
|
||||
qboolean R_AddBulleten (texture_t *textur);
|
||||
void R_MakeBulleten (texture_t *textur, int lefttext, int toptext, char *text, qbyte *background);
|
||||
//void R_MakeBulleten (texture_t *textur, int lefttext, int toptext, char *text);
|
||||
void R_SetupBulleten (void);
|
||||
void Draw_StringToMip(char *str, qbyte *mip, int x, int y, int width, int height);
|
||||
void Draw_CharToMip (int num, qbyte *mip, int x, int y, int width, int height);
|
||||
|
||||
void WipeBulletenTextures(void);
|
||||
void Bul_ParseMessage(void);
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_efrag.c
|
||||
|
||||
#include "quakedef.h"
|
||||
//#include "r_local.h"
|
||||
|
||||
extern int r_framecount;
|
||||
|
||||
mnode_t *r_pefragtopnode;
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
ENTITY FRAGMENT FUNCTIONS
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
efrag_t **lastlink;
|
||||
|
||||
vec3_t r_emins, r_emaxs;
|
||||
|
||||
entity_t *r_addent;
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RemoveEfrags
|
||||
|
||||
Call when removing an object from the world or moving it to another position
|
||||
================
|
||||
*/
|
||||
void R_RemoveEfrags (entity_t *ent)
|
||||
{
|
||||
efrag_t *ef, *old, *walk, **prev;
|
||||
|
||||
ef = ent->efrag;
|
||||
|
||||
while (ef)
|
||||
{
|
||||
prev = &ef->leaf->efrags;
|
||||
while (1)
|
||||
{
|
||||
walk = *prev;
|
||||
if (!walk)
|
||||
break;
|
||||
if (walk == ef)
|
||||
{ // remove this fragment
|
||||
*prev = ef->leafnext;
|
||||
break;
|
||||
}
|
||||
else
|
||||
prev = &walk->leafnext;
|
||||
}
|
||||
|
||||
old = ef;
|
||||
ef = ef->entnext;
|
||||
|
||||
// put it on the free list
|
||||
old->entnext = cl.free_efrags;
|
||||
cl.free_efrags = old;
|
||||
}
|
||||
|
||||
ent->efrag = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
R_SplitEntityOnNode
|
||||
===================
|
||||
*/
|
||||
void R_Q1Q2BSP_SplitEntityOnNode (mnode_t *node)
|
||||
{
|
||||
efrag_t *ef;
|
||||
mplane_t *splitplane;
|
||||
mleaf_t *leaf;
|
||||
int sides;
|
||||
|
||||
if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)
|
||||
{
|
||||
if (node->contents & Q2CONTENTS_SOLID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->contents == Q1CONTENTS_SOLID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// add an efrag if the node is a leaf
|
||||
|
||||
if ( node->contents < 0)
|
||||
{
|
||||
if (!r_pefragtopnode)
|
||||
r_pefragtopnode = node;
|
||||
|
||||
leaf = (mleaf_t *)node;
|
||||
|
||||
// grab an efrag off the free list
|
||||
ef = cl.free_efrags;
|
||||
if (!ef)
|
||||
{
|
||||
Con_Printf ("Too many efrags!\n");
|
||||
return; // no free fragments...
|
||||
}
|
||||
cl.free_efrags = cl.free_efrags->entnext;
|
||||
|
||||
ef->entity = r_addent;
|
||||
|
||||
// add the entity link
|
||||
*lastlink = ef;
|
||||
lastlink = &ef->entnext;
|
||||
ef->entnext = NULL;
|
||||
|
||||
// set the leaf links
|
||||
ef->leaf = leaf;
|
||||
ef->leafnext = leaf->efrags;
|
||||
leaf->efrags = ef;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// NODE_MIXED
|
||||
|
||||
splitplane = node->plane;
|
||||
sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
|
||||
|
||||
if (sides == 3)
|
||||
{
|
||||
// split on this plane
|
||||
// if this is the first splitter of this bmodel, remember it
|
||||
if (!r_pefragtopnode)
|
||||
r_pefragtopnode = node;
|
||||
}
|
||||
|
||||
// recurse down the contacted sides
|
||||
if (sides & 1)
|
||||
R_Q1Q2BSP_SplitEntityOnNode (node->children[0]);
|
||||
|
||||
if (sides & 2)
|
||||
R_Q1Q2BSP_SplitEntityOnNode (node->children[1]);
|
||||
}
|
||||
|
||||
#ifdef SWQUAKE
|
||||
/*
|
||||
===================
|
||||
R_SplitEntityOnNode2
|
||||
===================
|
||||
*/
|
||||
void R_Q1BSP_SplitEntityOnNode2 (mnode_t *node)
|
||||
{
|
||||
mplane_t *splitplane;
|
||||
int sides;
|
||||
|
||||
if (node->visframe != r_visframecount)
|
||||
return;
|
||||
|
||||
if (node->contents < 0)
|
||||
{
|
||||
if (node->contents != Q1CONTENTS_SOLID)
|
||||
r_pefragtopnode = node; // we've reached a non-solid leaf, so it's
|
||||
// visible and not BSP clipped
|
||||
return;
|
||||
}
|
||||
|
||||
splitplane = node->plane;
|
||||
sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
|
||||
|
||||
if (sides == 3)
|
||||
{
|
||||
// remember first splitter
|
||||
r_pefragtopnode = node;
|
||||
return;
|
||||
}
|
||||
|
||||
// not split yet; recurse down the contacted side
|
||||
if (sides & 1)
|
||||
R_Q1BSP_SplitEntityOnNode2 (node->children[0]);
|
||||
else
|
||||
R_Q1BSP_SplitEntityOnNode2 (node->children[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
===========
|
||||
R_AddEfrags
|
||||
===========
|
||||
*/
|
||||
void R_AddEfrags (entity_t *ent)
|
||||
{
|
||||
model_t *entmodel;
|
||||
int i;
|
||||
|
||||
if (!ent->model)
|
||||
return;
|
||||
|
||||
if (ent == &r_worldentity)
|
||||
return; // never add the world
|
||||
|
||||
r_addent = ent;
|
||||
|
||||
lastlink = &ent->efrag;
|
||||
r_pefragtopnode = NULL;
|
||||
|
||||
entmodel = ent->model;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
r_emins[i] = ent->origin[i] + entmodel->mins[i];
|
||||
r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
|
||||
}
|
||||
|
||||
if (cl.worldmodel->nodes)
|
||||
R_Q1Q2BSP_SplitEntityOnNode (cl.worldmodel->nodes);
|
||||
|
||||
ent->topnode = r_pefragtopnode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_StoreEfrags
|
||||
|
||||
// FIXME: a lot of this goes away with edge-based
|
||||
================
|
||||
*/
|
||||
void R_StoreEfrags (efrag_t **ppefrag)
|
||||
{
|
||||
entity_t *pent;
|
||||
model_t *clmodel;
|
||||
efrag_t *pefrag;
|
||||
|
||||
|
||||
while ((pefrag = *ppefrag) != NULL)
|
||||
{
|
||||
pent = pefrag->entity;
|
||||
clmodel = pent->model;
|
||||
|
||||
// switch (clmodel->type)
|
||||
// {
|
||||
// case mod_alias:
|
||||
// case mod_brush:
|
||||
// case mod_sprite:
|
||||
// pent = pefrag->entity;
|
||||
|
||||
if ((pent->visframe != r_framecount) &&
|
||||
(cl_numvisedicts < MAX_VISEDICTS))
|
||||
{
|
||||
cl_visedicts[cl_numvisedicts++] = *pent;
|
||||
|
||||
// mark that we've recorded this entity for this frame
|
||||
pent->visframe = r_framecount;
|
||||
}
|
||||
|
||||
ppefrag = &pefrag->leafnext;
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
|||
extern char *particle_set_spikeset;
|
||||
extern char *particle_set_highfps;
|
||||
extern char *particle_set_faithful;
|
||||
|
||||
// #define particle_set_faithful particle_set_highfps
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// refresh.h -- public interface to refresh functions
|
||||
|
||||
#define TOP_RANGE 16 // soldier uniform colors
|
||||
#define BOTTOM_RANGE 96
|
||||
|
||||
struct msurface_s;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef struct efrag_s
|
||||
{
|
||||
struct mleaf_s *leaf;
|
||||
struct efrag_s *leafnext;
|
||||
struct entity_s *entity;
|
||||
struct efrag_s *entnext;
|
||||
} efrag_t;
|
||||
|
||||
|
||||
typedef struct entity_s
|
||||
{
|
||||
int keynum; // for matching entities in different frames
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
|
||||
vec3_t oldorigin;
|
||||
vec3_t oldangles;
|
||||
|
||||
struct model_s *model; // NULL = no model
|
||||
int frame;
|
||||
qbyte *colormap;
|
||||
int skinnum; // for Alias models
|
||||
|
||||
struct player_info_s *scoreboard; // identify player
|
||||
|
||||
float syncbase;
|
||||
|
||||
struct efrag_s *efrag; // linked list of efrags (FIXME)
|
||||
int visframe; // last frame this entity was
|
||||
// found in an active leaf
|
||||
// only used for static objects
|
||||
|
||||
int dlightframe; // dynamic lighting
|
||||
int dlightbits;
|
||||
|
||||
// FIXME: could turn these into a union
|
||||
int trivial_accept;
|
||||
struct mnode_s *topnode; // for bmodels, first world node
|
||||
// that splits bmodel, or NULL if
|
||||
// not split
|
||||
|
||||
int flags;
|
||||
|
||||
#ifdef PEXT_SCALE
|
||||
float scale;
|
||||
#endif
|
||||
#ifdef PEXT_TRANS
|
||||
float alpha;
|
||||
#endif
|
||||
#ifdef PEXT_FATNESS
|
||||
float fatness;
|
||||
#endif
|
||||
#ifdef PEXT_HEXEN2
|
||||
int drawflags;
|
||||
int abslight;
|
||||
#endif
|
||||
float lerpfrac;
|
||||
float lerptime;
|
||||
int oldframe;
|
||||
} entity_t;
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct
|
||||
{
|
||||
vrect_t vrect; // subwindow in video for refresh
|
||||
// FIXME: not need vrect next field here?
|
||||
vrect_t aliasvrect; // scaled Alias version
|
||||
int vrectright, vrectbottom; // right & bottom screen coords
|
||||
int aliasvrectright, aliasvrectbottom; // scaled Alias versions
|
||||
float vrectrightedge; // rightmost right edge we care about,
|
||||
// for use in edge list
|
||||
float fvrectx, fvrecty; // for floating-point compares
|
||||
float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping
|
||||
int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20
|
||||
int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20
|
||||
float fvrectright_adj, fvrectbottom_adj;
|
||||
// right and bottom edges, for clamping
|
||||
float fvrectright; // rightmost edge, for Alias clamping
|
||||
float fvrectbottom; // bottommost edge, for Alias clamping
|
||||
float horizontalFieldOfView; // at Z = 1.0, this many X is visible
|
||||
// 2.0 = 90 degrees
|
||||
float xOrigin; // should probably allways be 0.5
|
||||
float yOrigin; // between be around 0.3 to 0.5
|
||||
|
||||
vec3_t vieworg;
|
||||
vec3_t viewangles;
|
||||
|
||||
float fov_x, fov_y;
|
||||
|
||||
int ambientlight;
|
||||
|
||||
int flags;
|
||||
|
||||
int currentplayernum;
|
||||
} refdef_t;
|
||||
|
||||
|
||||
//
|
||||
// refresh
|
||||
//
|
||||
extern int reinit_surfcache;
|
||||
|
||||
|
||||
extern refdef_t r_refdef;
|
||||
extern vec3_t r_origin, vpn, vright, vup;
|
||||
|
||||
extern struct texture_s *r_notexture_mip;
|
||||
|
||||
extern entity_t r_worldentity;
|
||||
|
||||
#if defined(RGLQUAKE)
|
||||
void GLR_Init (void);
|
||||
void GLR_ReInit (void);
|
||||
void GLR_InitTextures (void);
|
||||
void GLR_InitEfrags (void);
|
||||
void GLR_RenderView (void); // must set r_refdef first
|
||||
// called whenever r_refdef or vid change
|
||||
void GLR_InitSky (struct texture_s *mt); // called at level load
|
||||
void GLR_SetSky (char *name, float rotate, vec3_t axis);
|
||||
qboolean GLR_CheckSky(void);
|
||||
|
||||
void GLR_AddEfrags (entity_t *ent);
|
||||
void GLR_RemoveEfrags (entity_t *ent);
|
||||
|
||||
void GLR_NewMap (void);
|
||||
|
||||
void GLR_PushDlights (void);
|
||||
void GLR_DrawWaterSurfaces (void);
|
||||
|
||||
void GLR_AddStain(vec3_t org, float red, float green, float blue, float radius);
|
||||
void GLR_LessenStains(void);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SWQUAKE)
|
||||
void SWR_Init (void);
|
||||
void SWR_InitTextures (void);
|
||||
void SWR_InitEfrags (void);
|
||||
void SWR_RenderView (void); // must set r_refdef first
|
||||
void SWR_ViewChanged (vrect_t *pvrect, int lineadj, float aspect);
|
||||
// called whenever r_refdef or vid change
|
||||
void SWR_InitSky (struct texture_s *mt); // called at level load
|
||||
void SWR_SetSky (char *name, float rotate, vec3_t axis);
|
||||
qboolean SWR_CheckSky(void);
|
||||
|
||||
void SWR_AddEfrags (entity_t *ent);
|
||||
void SWR_RemoveEfrags (entity_t *ent);
|
||||
|
||||
void SWR_NewMap (void);
|
||||
|
||||
void SWR_PushDlights (void);
|
||||
|
||||
void SWR_AddStain(vec3_t org, float red, float green, float blue, float radius);
|
||||
void SWR_LessenStains(void);
|
||||
#endif
|
||||
void R_ParseParticleEffect (void);
|
||||
void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);
|
||||
|
||||
float R_RocketTrail (vec3_t start, vec3_t end, int type, float olddistance);
|
||||
int R_RunParticleEffectType(vec3_t org, vec3_t dir, float count, int type);
|
||||
void R_RunParticleEffect2 (vec3_t org, vec3_t dmin, vec3_t dmax, int color, int effect, int count);
|
||||
void R_RunParticleEffect3 (vec3_t org, vec3_t box, int color, int effect, int count);
|
||||
void R_RunParticleEffect4 (vec3_t org, float radius, int color, int effect, int count);
|
||||
int AllocateParticleType(char *name);
|
||||
|
||||
void R_DefaultTrail (struct model_s *model);
|
||||
void R_TorchEffect (vec3_t pos, int type);
|
||||
|
||||
void R_EntityParticles (float *org, qbyte colour, float *radius);
|
||||
void R_BlobExplosion (vec3_t org);
|
||||
qboolean R_EMPExplosion (vec3_t org);
|
||||
void R_ParticleExplosion (vec3_t org);
|
||||
void R_LavaSplash (vec3_t org);
|
||||
void R_TeleportSplash (vec3_t org);
|
||||
|
||||
void R_AddEfrags (entity_t *ent);
|
||||
void R_RemoveEfrags (entity_t *ent);
|
||||
|
||||
//
|
||||
// surface cache related
|
||||
//
|
||||
extern int reinit_surfcache; // if 1, surface cache is currently empty and
|
||||
extern qboolean r_cache_thrash; // set if thrashing the surface cache
|
||||
|
||||
int D_SurfaceCacheForRes (int width, int height, int bpp);
|
||||
void D_FlushCaches (void);
|
||||
void D_DeleteSurfaceCache (void);
|
||||
void D_InitCaches (void *buffer, int size);
|
||||
void R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(RGLQUAKE)
|
||||
|
||||
void GLMod_Init (void);
|
||||
void GLMod_ClearAll (void);
|
||||
struct model_s *GLMod_ForName (char *name, qboolean crash);
|
||||
struct model_s *GLMod_FindName (char *name);
|
||||
void *GLMod_Extradata (struct model_s *mod); // handles caching
|
||||
void GLMod_TouchModel (char *name);
|
||||
|
||||
struct mleaf_s *GLMod_PointInLeaf (float *p, struct model_s *model);
|
||||
qbyte *GLMod_LeafPVS (struct mleaf_s *leaf, struct model_s *model, qbyte *buffer);
|
||||
qbyte *GLMod_LeafnumPVS (int leafnum, struct model_s *model, qbyte *buffer);
|
||||
|
||||
void GLMod_Think (void);
|
||||
void GLMod_ReloadTextures(void);
|
||||
void GLMod_NowLoadExternal(void);
|
||||
void GLR_WipeStains(void);
|
||||
void R_LoadSkys (void);
|
||||
#endif
|
||||
|
||||
#if defined(SWQUAKE)
|
||||
|
||||
void SWMod_Init (void);
|
||||
void SWMod_ClearAll (void);
|
||||
struct model_s *SWMod_ForName (char *name, qboolean crash);
|
||||
struct model_s *SWMod_FindName (char *name);
|
||||
void *SWMod_Extradata (struct model_s *mod); // handles caching
|
||||
void SWMod_TouchModel (char *name);
|
||||
|
||||
struct mleaf_s *SWMod_PointInLeaf (float *p, struct model_s *model);
|
||||
qbyte *SWMod_LeafPVS (struct mleaf_s *leaf, struct model_s *model, qbyte *buffer);
|
||||
|
||||
void SWMod_Think (void);
|
||||
void SWMod_ReloadTextures(void);
|
||||
void SWMod_NowLoadExternal(void);
|
||||
#endif
|
||||
|
||||
qboolean Media_ShowFilm(void);
|
||||
void Media_ShowFrame(qbyte *framedata, int inwidth, int inheight, qbyte *bgrandupsidedown);
|
||||
void Media_ShowFrame8bit(qbyte *framedata, int inwidth, int inheight, qbyte *palette); //for media playback not based in m_mp3.c gotta rename that file...
|
||||
void Media_CaptureDemoEnd(void);
|
||||
void Media_RecordAudioFrame (short *sample_buffer, int samples);
|
||||
void Media_RecordFrame (void);
|
||||
void MakeVideoPalette(void);
|
||||
|
||||
void R_Part_SkyTri(float *v1, float *v2, float *v3, struct msurface_s *surf);
|
||||
void R_ClearParticles (void);
|
||||
void R_Part_NewServer(void);
|
||||
int ParticleTypeForName(char *name);
|
||||
void R_SetRenderer(r_qrenderer_t wanted);
|
||||
void R_DrawParticles (void);
|
||||
void R_InitParticles (void);
|
||||
void RQ_Init(void);
|
||||
void R_BlasterParticles (vec3_t org, vec3_t dir);
|
||||
void CLQ2_RailTrail (vec3_t start, vec3_t end);
|
||||
void CLQ2_BubbleTrail (vec3_t start, vec3_t end);
|
||||
void CLQ2_EntityEvent(entity_state_t *es);
|
||||
void CLQ2_TeleporterParticles(entity_state_t *es);
|
||||
void CLQ2_IonripperTrail(vec3_t oldorg, vec3_t neworg);
|
||||
void CLQ2_TrackerTrail(vec3_t oldorg, vec3_t neworg, int flags);
|
||||
void CLQ2_Tracker_Shell(vec3_t org);
|
||||
void CLQ2_TagTrail(vec3_t oldorg, vec3_t neworg, int flags);
|
||||
void CLQ2_FlagTrail(vec3_t oldorg, vec3_t neworg, int flags);
|
||||
void CLQ2_TrapParticles(entity_t *ent);
|
||||
void CLQ2_BfgParticles(entity_t *ent);
|
||||
struct q2centity_s;
|
||||
void CLQ2_FlyEffect(struct q2centity_s *ent, vec3_t org);
|
||||
void CLQ2_DiminishingTrail(vec3_t oldorg, vec3_t neworg, struct q2centity_s *ent, unsigned int effects);
|
||||
void CLQ2_BlasterTrail(vec3_t oldorg, vec3_t neworg);
|
||||
void CLQ2_BlasterTrail2(vec3_t oldorg, vec3_t neworg);
|
||||
void CLQ2_RocketTrail(vec3_t oldorg, vec3_t neworg, struct q2centity_s *ent);
|
||||
|
||||
void WritePCXfile (char *filename, qbyte *data, int width, int height, int rowbytes, qbyte *palette, qboolean upload); //data is 8bit.
|
||||
qbyte *ReadPCXFile(qbyte *buf, int length, int *width, int *height);
|
||||
qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, int asgrey);
|
||||
qbyte *ReadJPEGFile(qbyte *infile, int length, int *width, int *height);
|
||||
qbyte *ReadPNGFile(qbyte *buf, int length, int *width, int *height);
|
||||
qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out);
|
||||
|
||||
void BoostGamma(qbyte *rgba, int width, int height);
|
||||
|
||||
void CL_NewDlightRGB (int key, float x, float y, float z, float radius, float time,
|
||||
float r, float g, float b);
|
||||
|
||||
void Renderer_Init(void);
|
||||
|
||||
//used to live in glquake.h
|
||||
qbyte GetPalette(int red, int green, int blue);
|
||||
extern cvar_t r_norefresh;
|
||||
extern cvar_t r_drawentities;
|
||||
extern cvar_t r_drawworld;
|
||||
extern cvar_t r_drawviewmodel;
|
||||
extern cvar_t r_speeds;
|
||||
extern cvar_t r_waterwarp;
|
||||
extern cvar_t r_fullbright;
|
||||
extern cvar_t r_lightmap;
|
||||
extern cvar_t r_shadows;
|
||||
extern cvar_t r_mirroralpha;
|
||||
extern cvar_t r_wateralpha;
|
||||
extern cvar_t r_dynamic;
|
||||
extern cvar_t r_novis;
|
||||
extern cvar_t r_netgraph;
|
||||
|
||||
#ifdef R_XFLIP
|
||||
extern cvar_t r_xflip;
|
||||
#endif
|
||||
|
||||
extern cvar_t gl_clear;
|
||||
extern cvar_t gl_cull;
|
||||
extern cvar_t gl_poly;
|
||||
extern cvar_t gl_smoothmodels;
|
||||
extern cvar_t gl_affinemodels;
|
||||
extern cvar_t gl_polyblend;
|
||||
extern cvar_t gl_keeptjunctions;
|
||||
extern cvar_t gl_reporttjunctions;
|
||||
extern cvar_t r_flashblend;
|
||||
extern cvar_t gl_nocolors;
|
||||
extern cvar_t gl_load24bit;
|
||||
extern cvar_t gl_finish;
|
||||
|
||||
extern cvar_t gl_max_size;
|
||||
extern cvar_t gl_playermip;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,98 @@
|
|||
//this is to render transparent things in a distance oriented order
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "renderque.h"
|
||||
|
||||
#define NUMGRADUATIONS 0x400
|
||||
static renderque_t *freerque;
|
||||
static renderque_t *activerque;
|
||||
static renderque_t *initialque;
|
||||
|
||||
static renderque_t *distlastarque[NUMGRADUATIONS];
|
||||
static renderque_t *distrque[NUMGRADUATIONS];
|
||||
|
||||
int rqmaxgrad, rqmingrad;
|
||||
|
||||
int rquesize = 0x2000;
|
||||
|
||||
void RQ_AddDistReorder(void (*render) (void *, void *), void *data1, void *data2, float *pos)
|
||||
{
|
||||
int dist;
|
||||
vec3_t delta;
|
||||
renderque_t *rq;
|
||||
if (!freerque)
|
||||
{
|
||||
render(data1, data2);
|
||||
return;
|
||||
}
|
||||
|
||||
VectorSubtract(pos, r_refdef.vieworg, delta);
|
||||
dist = Length(delta)/4;
|
||||
|
||||
if (dist > rqmaxgrad)
|
||||
{
|
||||
if (dist >= NUMGRADUATIONS)
|
||||
dist = NUMGRADUATIONS-1;
|
||||
rqmaxgrad = dist;
|
||||
}
|
||||
if (dist < rqmingrad)
|
||||
{
|
||||
if (dist < 0) //hmm... value wrapped? shouldn't happen
|
||||
dist = 0;
|
||||
rqmingrad = dist;
|
||||
}
|
||||
|
||||
rq = freerque;
|
||||
freerque = freerque->next;
|
||||
rq->next = NULL;
|
||||
if (distlastarque[dist])
|
||||
distlastarque[dist]->next = rq;
|
||||
distlastarque[dist] = rq;
|
||||
|
||||
rq->render = render;
|
||||
rq->data1 = data1;
|
||||
rq->data2 = data2;
|
||||
|
||||
if (!distrque[dist])
|
||||
distrque[dist] = rq;
|
||||
}
|
||||
|
||||
void RQ_RenderDistAndClear(void)
|
||||
{
|
||||
int i;
|
||||
renderque_t *rq;
|
||||
for (i = rqmaxgrad; i>=rqmingrad; i--)
|
||||
{
|
||||
for (rq = distrque[i]; rq; rq=rq->next)
|
||||
{
|
||||
rq->render(rq->data1, rq->data2);
|
||||
}
|
||||
if (distlastarque[i])
|
||||
{
|
||||
distlastarque[i]->next = freerque;
|
||||
freerque = distrque[i];
|
||||
distrque[i] = NULL;
|
||||
distlastarque[i] = NULL;
|
||||
}
|
||||
}
|
||||
rqmaxgrad=0;
|
||||
rqmingrad = NUMGRADUATIONS-1;
|
||||
}
|
||||
|
||||
void RQ_Init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (initialque)
|
||||
return;
|
||||
|
||||
initialque = (renderque_t *) Hunk_AllocName (rquesize * sizeof(renderque_t), "renderque");
|
||||
|
||||
|
||||
freerque = &initialque[0];
|
||||
activerque = NULL;
|
||||
|
||||
for (i=0 ;i<rquesize-1 ; i++)
|
||||
initialque[i].next = &initialque[i+1];
|
||||
initialque[rquesize-1].next = NULL;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
void RQ_AddDistReorder(void (*render) (void *, void *), void *data1, void *data2, float *pos);
|
||||
|
||||
void RQ_RenderDistAndClear(void);
|
||||
|
||||
typedef struct renderque_s
|
||||
{
|
||||
struct renderque_s *next;
|
||||
void (*render) (void *data1, void *data2);
|
||||
void *data1;
|
||||
void *data2;
|
||||
} renderque_t;
|
|
@ -0,0 +1,23 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by winquake.rc
|
||||
//
|
||||
#define IDS_STRING1 1
|
||||
#define IDI_ICON2 1
|
||||
#define IDD_DIALOG1 108
|
||||
#define IDD_PROGRESS 109
|
||||
#define IDB_QWBITMAP 112
|
||||
#define IDI_ICON1 115
|
||||
#define IDB_BITMAP1 116
|
||||
#define IDC_PROGRESS 1000
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 121
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1005
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,622 @@
|
|||
/* ------------------------------------------------------------------------
|
||||
* Id Software's RoQ video file format decoder
|
||||
*
|
||||
* Dr. Tim Ferguson, 2001.
|
||||
* For more details on the algorithm:
|
||||
* http://www.csse.monash.edu.au/~timf/videocodec.html
|
||||
*
|
||||
* This is a simple decoder for the Id Software RoQ video format. In
|
||||
* this format, audio samples are DPCM coded and the video frames are
|
||||
* coded using motion blocks and vector quantisation.
|
||||
*
|
||||
* Note: All information on the RoQ file format has been obtained through
|
||||
* pure reverse engineering. This was achieved by giving known input
|
||||
* audio and video frames to the roq.exe encoder and analysing the
|
||||
* resulting output text and RoQ file. No decompiling of the Quake III
|
||||
* Arena game was required.
|
||||
*
|
||||
* You may freely use this source code. I only ask that you reference its
|
||||
* source in your projects documentation:
|
||||
* Tim Ferguson: http://www.csse.monash.edu.au/~timf/
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#include "bothdefs.h"
|
||||
|
||||
#ifndef NOMEDIA
|
||||
|
||||
//#include <stdio.h>
|
||||
//#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
#include "quakedef.h"
|
||||
#include "roq.h"
|
||||
|
||||
//#define DBUG 1
|
||||
|
||||
#define FAST
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static unsigned int get_word(FILE *fp)
|
||||
{
|
||||
unsigned int ret;
|
||||
|
||||
ret = ((fgetc(fp)) & 0xff);
|
||||
ret |= ((fgetc(fp)) & 0xff) << 8;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static unsigned long get_long(FILE *fp)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
ret = ((fgetc(fp)) & 0xff);
|
||||
ret |= ((fgetc(fp)) & 0xff) << 8;
|
||||
ret |= ((fgetc(fp)) & 0xff) << 16;
|
||||
ret |= ((fgetc(fp)) & 0xff) << 24;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static int roq_parse_file(FILE *fp, roq_info *ri)
|
||||
{
|
||||
unsigned int head1, head3, chunk_id, chunk_arg;
|
||||
long head2, chunk_size;
|
||||
long fpos;
|
||||
#ifndef FAST
|
||||
int max_frame;
|
||||
#endif
|
||||
|
||||
#define rfeof(f) (ftell(f)>= ri->maxpos)
|
||||
|
||||
#ifndef FAST
|
||||
ri->num_audio_bytes = ri->num_frames = max_frame = 0;
|
||||
ri->audio_channels = 0;
|
||||
ri->frame_offset = NULL;
|
||||
#endif
|
||||
ri->buf_size = 0;
|
||||
head1 = get_word(fp);
|
||||
head2 = get_long(fp);
|
||||
head3 = get_word(fp);
|
||||
if(head1 != 0x1084 && head2 != 0xffffffff && head3 != 0x1e)
|
||||
{
|
||||
Con_Printf("Not an RoQ file.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ri->roq_start = ftell(fp);
|
||||
while(!rfeof(fp))
|
||||
{
|
||||
#if DBUG > 20
|
||||
Con_Printf("---------------------------------------------------------------------------\n");
|
||||
#endif
|
||||
fpos = ftell(fp);
|
||||
chunk_id = get_word(fp);
|
||||
chunk_size = get_long(fp);
|
||||
chunk_arg = get_word(fp);
|
||||
if (chunk_size == -1) //FIXME: THIS SHOULD NOT HAPPEN
|
||||
break;
|
||||
if(chunk_size > ri->buf_size) ri->buf_size = chunk_size;
|
||||
if(rfeof(fp)) break;
|
||||
#if DBUG > 20
|
||||
Con_Printf("%03d 0x%06lx: chunk: 0x%02x size: %ld cells: 2x2=%d,4x4=%d\n", i,
|
||||
fpos, chunk_id, chunk_size, v1>>8,v1&0xff);
|
||||
#endif
|
||||
|
||||
if(chunk_id == RoQ_INFO) /* video info */
|
||||
{
|
||||
ri->width = get_word(fp);
|
||||
ri->height = get_word(fp);
|
||||
get_word(fp);
|
||||
get_word(fp);
|
||||
#ifdef FAST
|
||||
return 0; //we have all the data we need now. We always find a sound chunk first, or none at all.
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef FAST
|
||||
if(chunk_id == RoQ_QUAD_VQ)
|
||||
{
|
||||
ri->num_frames++;
|
||||
if(ri->num_frames > max_frame)
|
||||
{
|
||||
max_frame += 5000;
|
||||
if((ri->frame_offset = BZ_Realloc(ri->frame_offset, sizeof(long) * max_frame)) == NULL) return 1;
|
||||
}
|
||||
ri->frame_offset[ri->num_frames] = fpos;
|
||||
}
|
||||
#endif
|
||||
if(chunk_id == RoQ_SOUND_MONO || chunk_id == RoQ_SOUND_STEREO)
|
||||
{
|
||||
if(chunk_id == RoQ_SOUND_MONO) ri->audio_channels = 1;
|
||||
else ri->audio_channels = 2;
|
||||
#ifndef FAST
|
||||
ri->num_audio_bytes += chunk_size;
|
||||
#endif
|
||||
}
|
||||
fseek(fp, chunk_size, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void apply_vector_2x2(roq_info *ri, int x, int y, roq_cell *cell)
|
||||
{
|
||||
unsigned char *yptr;
|
||||
|
||||
yptr = ri->y[0] + (y * ri->width) + x;
|
||||
*yptr++ = cell->y0;
|
||||
*yptr++ = cell->y1;
|
||||
yptr += (ri->width - 2);
|
||||
*yptr++ = cell->y2;
|
||||
*yptr++ = cell->y3;
|
||||
ri->u[0][(y/2) * (ri->width/2) + x/2] = cell->u;
|
||||
ri->v[0][(y/2) * (ri->width/2) + x/2] = cell->v;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void apply_vector_4x4(roq_info *ri, int x, int y, roq_cell *cell)
|
||||
{
|
||||
unsigned long row_inc, c_row_inc;
|
||||
register unsigned char y0, y1, u, v;
|
||||
unsigned char *yptr, *uptr, *vptr;
|
||||
|
||||
yptr = ri->y[0] + (y * ri->width) + x;
|
||||
uptr = ri->u[0] + (y/2) * (ri->width/2) + x/2;
|
||||
vptr = ri->v[0] + (y/2) * (ri->width/2) + x/2;
|
||||
|
||||
row_inc = ri->width - 4;
|
||||
c_row_inc = (ri->width/2) - 2;
|
||||
*yptr++ = y0 = cell->y0; *uptr++ = u = cell->u; *vptr++ = v = cell->v;
|
||||
*yptr++ = y0;
|
||||
*yptr++ = y1 = cell->y1; *uptr++ = u; *vptr++ = v;
|
||||
*yptr++ = y1;
|
||||
|
||||
yptr += row_inc;
|
||||
|
||||
*yptr++ = y0;
|
||||
*yptr++ = y0;
|
||||
*yptr++ = y1;
|
||||
*yptr++ = y1;
|
||||
|
||||
yptr += row_inc; uptr += c_row_inc; vptr += c_row_inc;
|
||||
|
||||
*yptr++ = y0 = cell->y2; *uptr++ = u; *vptr++ = v;
|
||||
*yptr++ = y0;
|
||||
*yptr++ = y1 = cell->y3; *uptr++ = u; *vptr++ = v;
|
||||
*yptr++ = y1;
|
||||
|
||||
yptr += row_inc;
|
||||
|
||||
*yptr++ = y0;
|
||||
*yptr++ = y0;
|
||||
*yptr++ = y1;
|
||||
*yptr++ = y1;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void apply_motion_4x4(roq_info *ri, int x, int y, unsigned char mv, char mean_x, char mean_y)
|
||||
{
|
||||
int i, mx, my;
|
||||
unsigned char *pa, *pb;
|
||||
|
||||
mx = x + 8 - (mv >> 4) - mean_x;
|
||||
my = y + 8 - (mv & 0xf) - mean_y;
|
||||
|
||||
pa = ri->y[0] + (y * ri->width) + x;
|
||||
pb = ri->y[1] + (my * ri->width) + mx;
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
pa[0] = pb[0];
|
||||
pa[1] = pb[1];
|
||||
pa[2] = pb[2];
|
||||
pa[3] = pb[3];
|
||||
pa += ri->width;
|
||||
pb += ri->width;
|
||||
}
|
||||
|
||||
pa = ri->u[0] + (y/2) * (ri->width/2) + x/2;
|
||||
pb = ri->u[1] + (my/2) * (ri->width/2) + (mx + 1)/2;
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
pa[0] = pb[0];
|
||||
pa[1] = pb[1];
|
||||
pa += ri->width/2;
|
||||
pb += ri->width/2;
|
||||
}
|
||||
|
||||
pa = ri->v[0] + (y/2) * (ri->width/2) + x/2;
|
||||
pb = ri->v[1] + (my/2) * (ri->width/2) + (mx + 1)/2;
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
pa[0] = pb[0];
|
||||
pa[1] = pb[1];
|
||||
pa += ri->width/2;
|
||||
pb += ri->width/2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void apply_motion_8x8(roq_info *ri, int x, int y, unsigned char mv, char mean_x, char mean_y)
|
||||
{
|
||||
int mx, my, i;
|
||||
unsigned char *pa, *pb;
|
||||
|
||||
mx = x + 8 - (mv >> 4) - mean_x;
|
||||
my = y + 8 - (mv & 0xf) - mean_y;
|
||||
|
||||
pa = ri->y[0] + (y * ri->width) + x;
|
||||
pb = ri->y[1] + (my * ri->width) + mx;
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
pa[0] = pb[0];
|
||||
pa[1] = pb[1];
|
||||
pa[2] = pb[2];
|
||||
pa[3] = pb[3];
|
||||
pa[4] = pb[4];
|
||||
pa[5] = pb[5];
|
||||
pa[6] = pb[6];
|
||||
pa[7] = pb[7];
|
||||
pa += ri->width;
|
||||
pb += ri->width;
|
||||
}
|
||||
|
||||
pa = ri->u[0] + (y/2) * (ri->width/2) + x/2;
|
||||
pb = ri->u[1] + (my/2) * (ri->width/2) + (mx + 1)/2;
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
pa[0] = pb[0];
|
||||
pa[1] = pb[1];
|
||||
pa[2] = pb[2];
|
||||
pa[3] = pb[3];
|
||||
pa += ri->width/2;
|
||||
pb += ri->width/2;
|
||||
}
|
||||
|
||||
pa = ri->v[0] + (y/2) * (ri->width/2) + x/2;
|
||||
pb = ri->v[1] + (my/2) * (ri->width/2) + (mx + 1)/2;
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
pa[0] = pb[0];
|
||||
pa[1] = pb[1];
|
||||
pa[2] = pb[2];
|
||||
pa[3] = pb[3];
|
||||
pa += ri->width/2;
|
||||
pb += ri->width/2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
roq_info *roq_open(char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
roq_info *ri;
|
||||
int i;
|
||||
|
||||
if (COM_FOpenFile(fname, &fp)==-1)
|
||||
// if((fp = fopen(fname, "rb")) == NULL)
|
||||
{
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if((ri = BZF_Malloc(sizeof(roq_info))) == NULL)
|
||||
{
|
||||
Con_Printf("Error allocating memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ri, 0, sizeof(roq_info));
|
||||
|
||||
ri->maxpos = ftell(fp)+com_filesize;//no adds/subracts for fileoffset here
|
||||
|
||||
ri->fp = fp;
|
||||
if(roq_parse_file(fp, ri)) return NULL;
|
||||
#ifndef FAST
|
||||
ri->stream_length = (ri->num_frames * 1000)/30;
|
||||
#endif
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
ri->snd_sqr_arr[i] = i * i;
|
||||
ri->snd_sqr_arr[i + 128] = -(i * i);
|
||||
}
|
||||
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
if((ri->y[i] = BZF_Malloc(ri->width * ri->height)) == NULL ||
|
||||
(ri->u[i] = BZF_Malloc((ri->width * ri->height)/4)) == NULL ||
|
||||
(ri->v[i] = BZF_Malloc((ri->width * ri->height)/4)) == NULL)
|
||||
{
|
||||
Con_Printf("Memory allocation error.\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ri->buf_size *= 2;
|
||||
if((ri->buf = BZF_Malloc(ri->buf_size)) == NULL)
|
||||
{
|
||||
Con_Printf("Memory allocation error.\n");
|
||||
return NULL;
|
||||
}
|
||||
ri->audio_buf_size = 0;
|
||||
ri->audio = NULL;
|
||||
|
||||
ri->frame_num = 0;
|
||||
ri->aud_pos = ri->vid_pos = ri->roq_start;
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
void roq_close(roq_info *ri)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(ri == NULL) return;
|
||||
fclose(ri->fp);
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
if(ri->y[i] != NULL) BZ_Free(ri->y[i]);
|
||||
if(ri->u[i] != NULL) BZ_Free(ri->u[i]);
|
||||
if(ri->v[i] != NULL) BZ_Free(ri->v[i]);
|
||||
}
|
||||
if(ri->buf != NULL) BZ_Free(ri->buf);
|
||||
BZ_Free(ri);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int roq_read_frame(roq_info *ri)
|
||||
{
|
||||
FILE *fp = ri->fp;
|
||||
unsigned int chunk_id = 0, chunk_arg = 0;
|
||||
unsigned long chunk_size = 0;
|
||||
int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1, vqid, bpos, xpos, ypos, xp, yp, x, y;
|
||||
unsigned char *tp, *buf;
|
||||
int frame_stats[2][4] = {{0},{0}};
|
||||
roq_qcell *qcell;
|
||||
|
||||
fseek(fp, ri->vid_pos, SEEK_SET);
|
||||
|
||||
while(!rfeof(fp))
|
||||
{
|
||||
chunk_id = get_word(fp);
|
||||
chunk_size = get_long(fp);
|
||||
chunk_arg = get_word(fp);
|
||||
if (chunk_size == 0xffffffff)
|
||||
return -1;
|
||||
if(rfeof(fp)) break;
|
||||
if(chunk_id == RoQ_QUAD_VQ) break;
|
||||
if(chunk_id == RoQ_QUAD_CODEBOOK)
|
||||
{
|
||||
if((nv1 = chunk_arg >> 8) == 0) nv1 = 256;
|
||||
if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size) nv2 = 256;
|
||||
for(i = 0; i < nv1; i++)
|
||||
{
|
||||
ri->cells[i].y0 = fgetc(fp);
|
||||
ri->cells[i].y1 = fgetc(fp);
|
||||
ri->cells[i].y2 = fgetc(fp);
|
||||
ri->cells[i].y3 = fgetc(fp);
|
||||
ri->cells[i].u = fgetc(fp);
|
||||
ri->cells[i].v = fgetc(fp);
|
||||
}
|
||||
for(i = 0; i < nv2; i++)
|
||||
for(j = 0; j < 4; j++) ri->qcells[i].idx[j] = fgetc(fp);
|
||||
}
|
||||
else fseek(fp, chunk_size, SEEK_CUR);
|
||||
}
|
||||
|
||||
if(chunk_id != RoQ_QUAD_VQ)
|
||||
{
|
||||
ri->vid_pos = ftell(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ri->frame_num++;
|
||||
if(ri->buf_size < chunk_size)
|
||||
{
|
||||
ri->buf_size *= 2;
|
||||
if (ri->buf_size < chunk_size) //double wasn't enough
|
||||
ri->buf_size = chunk_size;
|
||||
BZ_Free(ri->buf);
|
||||
if((ri->buf = BZ_Malloc(ri->buf_size)) == NULL)
|
||||
{
|
||||
Con_Printf("Memory allocation error.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
fread(ri->buf, chunk_size, 1, fp);
|
||||
buf = ri->buf;
|
||||
|
||||
bpos = xpos = ypos = 0;
|
||||
while(bpos < chunk_size)
|
||||
{
|
||||
for(yp = ypos; yp < ypos + 16; yp += 8)
|
||||
for(xp = xpos; xp < xpos + 16; xp += 8)
|
||||
{
|
||||
if(vqflg_pos < 0)
|
||||
{
|
||||
vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8);
|
||||
vqflg_pos = 7;
|
||||
}
|
||||
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
|
||||
frame_stats[0][vqid]++;
|
||||
vqflg_pos--;
|
||||
|
||||
switch(vqid)
|
||||
{
|
||||
case RoQ_ID_MOT: break;
|
||||
case RoQ_ID_FCC:
|
||||
apply_motion_8x8(ri, xp, yp, buf[bpos++], (char)(chunk_arg >> 8), (char)(chunk_arg & 0xff));
|
||||
break;
|
||||
case RoQ_ID_SLD:
|
||||
qcell = ri->qcells + buf[bpos++];
|
||||
apply_vector_4x4(ri, xp, yp, ri->cells + qcell->idx[0]);
|
||||
apply_vector_4x4(ri, xp+4, yp, ri->cells + qcell->idx[1]);
|
||||
apply_vector_4x4(ri, xp, yp+4, ri->cells + qcell->idx[2]);
|
||||
apply_vector_4x4(ri, xp+4, yp+4, ri->cells + qcell->idx[3]);
|
||||
break;
|
||||
case RoQ_ID_CCC:
|
||||
for(k = 0; k < 4; k++)
|
||||
{
|
||||
x = xp; y = yp;
|
||||
if(k & 0x01) x += 4;
|
||||
if(k & 0x02) y += 4;
|
||||
|
||||
if(vqflg_pos < 0)
|
||||
{
|
||||
vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8);
|
||||
vqflg_pos = 7;
|
||||
}
|
||||
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
|
||||
frame_stats[1][vqid]++;
|
||||
vqflg_pos--;
|
||||
switch(vqid)
|
||||
{
|
||||
case RoQ_ID_MOT: break;
|
||||
case RoQ_ID_FCC:
|
||||
apply_motion_4x4(ri, x, y, buf[bpos++], (char)(chunk_arg >> 8), (char)(chunk_arg & 0xff));
|
||||
break;
|
||||
case RoQ_ID_SLD:
|
||||
qcell = ri->qcells + buf[bpos++];
|
||||
apply_vector_2x2(ri, x, y, ri->cells + qcell->idx[0]);
|
||||
apply_vector_2x2(ri, x+2, y, ri->cells + qcell->idx[1]);
|
||||
apply_vector_2x2(ri, x, y+2, ri->cells + qcell->idx[2]);
|
||||
apply_vector_2x2(ri, x+2, y+2, ri->cells + qcell->idx[3]);
|
||||
break;
|
||||
case RoQ_ID_CCC:
|
||||
apply_vector_2x2(ri, x, y, ri->cells + buf[bpos]);
|
||||
apply_vector_2x2(ri, x+2, y, ri->cells + buf[bpos+1]);
|
||||
apply_vector_2x2(ri, x, y+2, ri->cells + buf[bpos+2]);
|
||||
apply_vector_2x2(ri, x+2, y+2, ri->cells + buf[bpos+3]);
|
||||
bpos += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Con_Printf("Unknown vq code: %d\n", vqid);
|
||||
}
|
||||
}
|
||||
|
||||
xpos += 16;
|
||||
if(xpos >= ri->width)
|
||||
{
|
||||
xpos -= ri->width;
|
||||
ypos += 16;
|
||||
}
|
||||
if(ypos >= ri->height) break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
frame_stats[0][3] = 0;
|
||||
Con_Printf("<%d 0x%04x -> %d,%d>\n", ri->frame_num, chunk_arg, (char)(chunk_arg >> 8), (char)(chunk_arg & 0xff));
|
||||
Con_Printf("for 08x08 CCC = %d, FCC = %d, MOT = %d, SLD = %d, PAT = 0\n", frame_stats[0][3], frame_stats[0][1], frame_stats[0][0], frame_stats[0][2]);
|
||||
Con_Printf("for 04x04 CCC = %d, FCC = %d, MOT = %d, SLD = %d, PAT = 0\n", frame_stats[1][3], frame_stats[1][1], frame_stats[1][0], frame_stats[1][2]);
|
||||
#endif
|
||||
|
||||
ri->vid_pos = ftell(fp);
|
||||
|
||||
if(ri->frame_num == 1)
|
||||
{
|
||||
memcpy(ri->y[1], ri->y[0], ri->width * ri->height);
|
||||
memcpy(ri->u[1], ri->u[0], (ri->width * ri->height)/4);
|
||||
memcpy(ri->v[1], ri->v[0], (ri->width * ri->height)/4);
|
||||
}
|
||||
else
|
||||
{
|
||||
tp = ri->y[0]; ri->y[0] = ri->y[1]; ri->y[1] = tp;
|
||||
tp = ri->u[0]; ri->u[0] = ri->u[1]; ri->u[1] = tp;
|
||||
tp = ri->v[0]; ri->v[0] = ri->v[1]; ri->v[1] = tp;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int roq_read_audio(roq_info *ri)
|
||||
{
|
||||
FILE *fp = ri->fp;
|
||||
unsigned int chunk_id = 0, chunk_arg = 0;
|
||||
unsigned long chunk_size = 0;
|
||||
int i, snd_left, snd_right;
|
||||
|
||||
fseek(fp, ri->aud_pos, SEEK_SET);
|
||||
ri->audio_size = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(rfeof(fp))
|
||||
return -1;
|
||||
chunk_id = get_word(fp);
|
||||
chunk_size = get_long(fp);
|
||||
chunk_arg = get_word(fp);
|
||||
if (chunk_size == 0xffffffff)
|
||||
return -1;
|
||||
if(rfeof(fp))
|
||||
return -1;
|
||||
if (chunk_id == RoQ_SOUND_MONO || chunk_id == RoQ_SOUND_STEREO)
|
||||
break;
|
||||
fseek(fp, chunk_size, SEEK_CUR);
|
||||
}
|
||||
|
||||
if(ri->audio_buf_size < chunk_size * 2)
|
||||
{
|
||||
if(ri->audio != NULL) BZ_Free(ri->audio);
|
||||
ri->audio=NULL;
|
||||
ri->audio_buf_size = chunk_size * 3;
|
||||
if (ri->audio_buf_size <= 0)
|
||||
return -1;
|
||||
if((ri->audio = BZ_Malloc(ri->audio_buf_size)) == NULL) return -1;
|
||||
}
|
||||
if (ri->audio_buf_size < 0)
|
||||
return -1;
|
||||
|
||||
if(chunk_id == RoQ_SOUND_MONO)
|
||||
{
|
||||
ri->audio_size = chunk_size * 2;
|
||||
snd_left = chunk_arg;
|
||||
for(i = 0; i < chunk_size; i++)
|
||||
{
|
||||
snd_left += ri->snd_sqr_arr[fgetc(fp)];
|
||||
ri->audio[i * 2] = snd_left & 0xff;
|
||||
ri->audio[i * 2 + 1] = (snd_left & 0xff00) >> 8;
|
||||
}
|
||||
ri->aud_pos = ftell(fp);
|
||||
return chunk_size;
|
||||
}
|
||||
|
||||
if(chunk_id == RoQ_SOUND_STEREO)
|
||||
{
|
||||
ri->audio_size = chunk_size * 2;
|
||||
snd_left = (chunk_arg & 0xFF00);
|
||||
snd_right = (chunk_arg & 0xFF) << 8;
|
||||
for(i = 0; i < chunk_size; i += 2)
|
||||
{
|
||||
snd_left += ri->snd_sqr_arr[fgetc(fp)];
|
||||
snd_right += ri->snd_sqr_arr[fgetc(fp)];
|
||||
ri->audio[i * 2] = snd_left & 0xff;
|
||||
ri->audio[i * 2 + 1] = (snd_left & 0xff00) >> 8;
|
||||
ri->audio[i * 2 + 2] = snd_right & 0xff;
|
||||
ri->audio[i * 2 + 3] = (snd_right & 0xff00) >> 8;
|
||||
}
|
||||
ri->aud_pos = ftell(fp);
|
||||
return chunk_size/2;
|
||||
}
|
||||
|
||||
ri->aud_pos = ftell(fp);
|
||||
return 0;
|
||||
}
|
||||
#undef rfeof
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// the status bar is only redrawn if something has changed, but if anything
|
||||
// does, the entire thing will be redrawn for the next vid.numpages frames.
|
||||
|
||||
#define SBAR_HEIGHT 24
|
||||
|
||||
extern int sb_lines; // scan lines to draw
|
||||
|
||||
void Sbar_Init (void);
|
||||
#ifdef RGLQUAKE
|
||||
void Sbar_ReInit (void);
|
||||
#endif
|
||||
|
||||
void Sbar_Changed (void);
|
||||
// call whenever any of the client stats represented on the sbar changes
|
||||
|
||||
void Sbar_Draw (void);
|
||||
// called every frame by screen
|
||||
|
||||
void Sbar_IntermissionOverlay (void);
|
||||
// called each frame after the level has been completed
|
||||
|
||||
void Sbar_FinaleOverlay (void);
|
||||
void Sbar_SortFrags (qboolean includespec);
|
||||
|
||||
void Sbar_Start (void);
|
||||
void Sbar_Flush (void);
|
||||
int Sbar_ColorForMap (int m);
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// screen.h
|
||||
|
||||
|
||||
extern float scr_con_current;
|
||||
extern float scr_conlines; // lines of console to display
|
||||
|
||||
extern int scr_fullupdate; // set to 0 to force full redraw
|
||||
extern int sb_lines;
|
||||
|
||||
extern int clearnotify; // set to 0 whenever notify text is drawn
|
||||
extern qboolean scr_disabled_for_loading;
|
||||
|
||||
extern cvar_t scr_fov;
|
||||
extern cvar_t scr_viewsize;
|
||||
|
||||
extern cvar_t scr_viewsize;
|
||||
|
||||
// only the refresh window will be updated unless these variables are flagged
|
||||
extern int scr_copytop;
|
||||
extern int scr_copyeverything;
|
||||
|
||||
qboolean scr_skipupdate;
|
||||
|
||||
qboolean SCR_RSShot (void);
|
||||
qboolean block_drawing;
|
||||
|
||||
//void SCR_DrawConsole (qboolean noback);
|
||||
//void SCR_SetUpToDrawConsole (void);
|
||||
|
||||
//void SCR_BeginLoadingPlaque (void);
|
||||
//void SCR_EndLoadingPlaque (void);
|
||||
|
||||
|
||||
//void SCR_Init (void);
|
||||
|
||||
//void SCR_UpdateScreen (void);
|
||||
|
||||
#if defined(RGLQUAKE)
|
||||
void GLSCR_UpdateScreen (void);
|
||||
#endif
|
||||
|
||||
void SCR_ImageName (char *mapname);
|
||||
|
||||
#if defined(SWQUAKE)
|
||||
void SWSCR_UpdateScreen (void);
|
||||
void SCR_UpdateWholeScreen (void);
|
||||
#endif
|
||||
|
||||
|
||||
//this stuff is internal to the screen systems.
|
||||
|
||||
void SCR_DrawLoading (void);
|
||||
void SCR_CalcRefdef (void);
|
||||
void SCR_TileClear (void);
|
||||
void SCR_DrawNotifyString (void);
|
||||
void SCR_CheckDrawCenterString (void);
|
||||
void SCR_DrawRam (void);
|
||||
void SCR_DrawNet (void);
|
||||
void SCR_DrawFPS (void);
|
||||
void SCR_DrawTurtle (void);
|
||||
void SCR_DrawPause (void);
|
||||
|
|
@ -0,0 +1,424 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
cvar_t baseskin = {"baseskin", "base"};
|
||||
cvar_t noskins = {"noskins", "0"};
|
||||
|
||||
extern cvar_t r_fb_models;
|
||||
|
||||
char allskins[128];
|
||||
#define MAX_CACHED_SKINS 128
|
||||
skin_t skins[MAX_CACHED_SKINS];
|
||||
int numskins;
|
||||
|
||||
/*
|
||||
================
|
||||
Skin_Find
|
||||
|
||||
Determines the best skin for the given scoreboard
|
||||
slot, and sets scoreboard->skin
|
||||
|
||||
================
|
||||
*/
|
||||
void Skin_Find (player_info_t *sc)
|
||||
{
|
||||
skin_t *skin;
|
||||
int i;
|
||||
char name[128], *s;
|
||||
|
||||
if (allskins[0])
|
||||
strcpy (name, allskins);
|
||||
else
|
||||
{
|
||||
s = Info_ValueForKey (sc->userinfo, "skin");
|
||||
if (s && s[0])
|
||||
strcpy (name, s);
|
||||
else
|
||||
strcpy (name, baseskin.string);
|
||||
}
|
||||
|
||||
if (strstr (name, "..") || *name == '.')
|
||||
strcpy (name, "base");
|
||||
|
||||
COM_StripExtension (name, name);
|
||||
|
||||
for (i=0 ; i<numskins ; i++)
|
||||
{
|
||||
if (!strcmp (name, skins[i].name))
|
||||
{
|
||||
sc->skin = &skins[i];
|
||||
Skin_Cache8 (sc->skin);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (numskins == MAX_CACHED_SKINS)
|
||||
{ // ran out of spots, so flush everything
|
||||
Skin_Skins_f ();
|
||||
return;
|
||||
}
|
||||
|
||||
skin = &skins[numskins];
|
||||
sc->skin = skin;
|
||||
numskins++;
|
||||
|
||||
memset (skin, 0, sizeof(*skin));
|
||||
Q_strncpyz(skin->name, name, sizeof(skin->name));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==========
|
||||
Skin_Cache
|
||||
|
||||
Returns a pointer to the skin bitmap, or NULL to use the default
|
||||
==========
|
||||
*/
|
||||
qbyte *Skin_Cache8 (skin_t *skin)
|
||||
{
|
||||
char name[1024];
|
||||
qbyte *raw;
|
||||
qbyte *out, *pix;
|
||||
pcx_t *pcx;
|
||||
int x, y;
|
||||
int dataByte;
|
||||
int runLength;
|
||||
int fbremap[256];
|
||||
|
||||
if (cls.downloadtype == dl_skin)
|
||||
return NULL; // use base until downloaded
|
||||
|
||||
if (noskins.value==1) // JACK: So NOSKINS > 1 will show skins, but
|
||||
return NULL; // not download new ones.
|
||||
|
||||
if (skin->failedload)
|
||||
return NULL;
|
||||
|
||||
out = Cache_Check (&skin->cache);
|
||||
if (out)
|
||||
return out;
|
||||
|
||||
#ifdef SWQUAKE
|
||||
if (qrenderer == QR_SOFTWARE && r_pixbytes == 1) //only time FB has to exist... (gl can be disabled)
|
||||
{
|
||||
for (x = 0; x < vid.fullbright; x++)
|
||||
fbremap[x] = GetPalette(host_basepal[((x+256-vid.fullbright)*3)], host_basepal[((x+256-vid.fullbright)*3)+1], host_basepal[((x+256-vid.fullbright)*3)+2]);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (x = 0; x < vid.fullbright; x++)
|
||||
fbremap[x] = x + (256-vid.fullbright); //fullbrights don't exist, so don't loose palette info.
|
||||
}
|
||||
|
||||
//
|
||||
// load the pic from disk
|
||||
//
|
||||
// sprintf (name, "players/male/%s.pcx", skin->name);
|
||||
sprintf (name, "skins/%s.pcx", skin->name);
|
||||
raw = COM_LoadTempFile (name);
|
||||
if (!raw)
|
||||
{
|
||||
Con_Printf ("Couldn't load skin %s\n", name);
|
||||
sprintf (name, "skins/%s.pcx", baseskin.string);
|
||||
raw = COM_LoadTempFile (name);
|
||||
if (!raw)
|
||||
{
|
||||
skin->failedload = true;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// parse the PCX file
|
||||
//
|
||||
pcx = (pcx_t *)raw;
|
||||
raw = (qbyte *)(pcx+1);
|
||||
|
||||
if (pcx->manufacturer != 0x0a
|
||||
|| pcx->version != 5
|
||||
|| pcx->encoding != 1
|
||||
|| pcx->bits_per_pixel != 8
|
||||
|| pcx->xmax >= 320
|
||||
|| pcx->ymax >= 200)
|
||||
{
|
||||
skin->failedload = true;
|
||||
Con_Printf ("Bad skin %s\n", name);
|
||||
return NULL;
|
||||
}
|
||||
skin->width = 320;
|
||||
skin->height = 200;
|
||||
skin->cachedbpp = 8;
|
||||
|
||||
out = Cache_Alloc (&skin->cache, 320*200, skin->name);
|
||||
if (!out)
|
||||
Sys_Error ("Skin_Cache: couldn't allocate");
|
||||
|
||||
pix = out;
|
||||
memset (out, 0, 320*200);
|
||||
|
||||
for (y=0 ; y<pcx->ymax ; y++, pix += 320)
|
||||
{
|
||||
for (x=0 ; x<=pcx->xmax ; )
|
||||
{
|
||||
if (raw - (qbyte*)pcx > com_filesize)
|
||||
{
|
||||
Cache_Free (&skin->cache);
|
||||
skin->failedload = true;
|
||||
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
|
||||
return NULL;
|
||||
}
|
||||
dataByte = *raw++;
|
||||
|
||||
if((dataByte & 0xC0) == 0xC0)
|
||||
{
|
||||
runLength = dataByte & 0x3F;
|
||||
if (raw - (qbyte*)pcx > com_filesize)
|
||||
{
|
||||
Cache_Free (&skin->cache);
|
||||
skin->failedload = true;
|
||||
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
|
||||
return NULL;
|
||||
}
|
||||
dataByte = *raw++;
|
||||
}
|
||||
else
|
||||
runLength = 1;
|
||||
|
||||
// skin sanity check
|
||||
if (runLength + x > pcx->xmax + 2) {
|
||||
Cache_Free (&skin->cache);
|
||||
skin->failedload = true;
|
||||
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dataByte >= 256-vid.fullbright) //kill the fb componant
|
||||
if (!r_fb_models.value)
|
||||
dataByte = fbremap[dataByte + vid.fullbright-256];
|
||||
|
||||
while(runLength-- > 0)
|
||||
pix[x++] = dataByte;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( raw - (qbyte *)pcx > com_filesize)
|
||||
{
|
||||
Cache_Free (&skin->cache);
|
||||
skin->failedload = true;
|
||||
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
skin->failedload = false;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
qbyte *Skin_Cache32 (skin_t *skin)
|
||||
{
|
||||
char name[1024];
|
||||
qbyte *raw;
|
||||
qbyte *out, *pix;
|
||||
|
||||
if (cls.downloadtype == dl_skin)
|
||||
return NULL; // use base until downloaded
|
||||
|
||||
if (noskins.value==1) // JACK: So NOSKINS > 1 will show skins, but
|
||||
return NULL; // not download new ones.
|
||||
|
||||
if (skin->failedload)
|
||||
return NULL;
|
||||
|
||||
out = Cache_Check (&skin->cache);
|
||||
if (out)
|
||||
return out;
|
||||
|
||||
//
|
||||
// load the pic from disk
|
||||
//
|
||||
sprintf (name, "skins/%s.tga", skin->name);
|
||||
raw = COM_LoadTempFile (name);
|
||||
if (raw)
|
||||
{
|
||||
pix = ReadTargaFile(raw, com_filesize, &skin->width, &skin->height, false);
|
||||
if (pix)
|
||||
{
|
||||
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
||||
memcpy(out, pix, skin->width*skin->height*4);
|
||||
BZ_Free(pix);
|
||||
}
|
||||
}
|
||||
#ifdef AVAIL_PNGLIB
|
||||
sprintf (name, "skins/%s.png", skin->name);
|
||||
raw = COM_LoadTempFile (name);
|
||||
if (raw)
|
||||
{
|
||||
pix = ReadPNGFile(raw, com_filesize, &skin->width, &skin->height);
|
||||
if (pix)
|
||||
{
|
||||
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
||||
memcpy(out, pix, skin->width*skin->height*4);
|
||||
BZ_Free(pix);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef AVAIL_JPEGLIB
|
||||
sprintf (name, "skins/%s.jpeg", skin->name);
|
||||
raw = COM_LoadTempFile (name);
|
||||
if (raw)
|
||||
{
|
||||
pix = ReadJPEGFile(raw, com_filesize, &skin->width, &skin->height);
|
||||
if (pix)
|
||||
{
|
||||
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
||||
memcpy(out, pix, skin->width*skin->height*4);
|
||||
BZ_Free(pix);
|
||||
}
|
||||
}
|
||||
sprintf (name, "skins/%s.jpg", skin->name); //jpegs are gready with 2 extensions...
|
||||
raw = COM_LoadTempFile (name);
|
||||
if (raw)
|
||||
{
|
||||
pix = ReadJPEGFile(raw, com_filesize, &skin->width, &skin->height);
|
||||
if (pix)
|
||||
{
|
||||
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
||||
memcpy(out, pix, skin->width*skin->height*4);
|
||||
BZ_Free(pix);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
skin->failedload = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Skin_NextDownload
|
||||
=================
|
||||
*/
|
||||
void Skin_NextDownload (void)
|
||||
{
|
||||
player_info_t *sc;
|
||||
int i;
|
||||
|
||||
if (cls.downloadnumber == 0)
|
||||
Con_Printf ("Checking skins...\n");
|
||||
cls.downloadtype = dl_skin;
|
||||
|
||||
for (
|
||||
; cls.downloadnumber != MAX_CLIENTS
|
||||
; cls.downloadnumber++)
|
||||
{
|
||||
sc = &cl.players[cls.downloadnumber];
|
||||
if (!sc->name[0])
|
||||
continue;
|
||||
Skin_Find (sc);
|
||||
if (noskins.value)
|
||||
continue;
|
||||
if (!CL_CheckOrDownloadFile(va("skins/%s.pcx", sc->skin->name), false))
|
||||
return; // started a download
|
||||
}
|
||||
|
||||
cls.downloadtype = dl_none;
|
||||
|
||||
// now load them in for real
|
||||
for (i=0 ; i<MAX_CLIENTS ; i++)
|
||||
{
|
||||
sc = &cl.players[i];
|
||||
if (!sc->name[0])
|
||||
continue;
|
||||
Skin_Cache8 (sc->skin);
|
||||
#ifdef RGLQUAKE
|
||||
sc->skin = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cls.state != ca_active)
|
||||
{ // get next signon phase
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
MSG_WriteString (&cls.netchan.message,
|
||||
va("begin %i", cl.servercount));
|
||||
Cache_Report (); // print remaining memory
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==========
|
||||
Skin_Skins_f
|
||||
|
||||
Refind all skins, downloading if needed.
|
||||
==========
|
||||
*/
|
||||
void Skin_Skins_f (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<numskins ; i++)
|
||||
{
|
||||
if (skins[i].cache.data)
|
||||
Cache_Free (&skins[i].cache);
|
||||
}
|
||||
numskins = 0;
|
||||
|
||||
cls.downloadnumber = 0;
|
||||
cls.downloadtype = dl_skin;
|
||||
Skin_NextDownload ();
|
||||
|
||||
#ifdef VM_CG
|
||||
CG_Stop();
|
||||
CG_Start();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==========
|
||||
Skin_AllSkins_f
|
||||
|
||||
Sets all skins to one specific one
|
||||
==========
|
||||
*/
|
||||
void Skin_AllSkins_f (void)
|
||||
{
|
||||
strcpy (allskins, Cmd_Argv(1));
|
||||
Skin_Skins_f ();
|
||||
}
|
||||
|
||||
void Skin_FlushSkin(char *name)
|
||||
{
|
||||
int i;
|
||||
char sname[16]="";
|
||||
if (strncmp(name, "skins/", 6))
|
||||
return;
|
||||
Q_strncpyz(sname, (name + 6), strlen(name+6)-3);
|
||||
for (i=0 ; i<numskins ; i++)
|
||||
{
|
||||
if (!strcmp(skins[i].name, sname))
|
||||
skins[i].failedload = false;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,434 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// snd_mem.c: sound caching
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
#include "winquake.h"
|
||||
|
||||
int cache_full_cycle;
|
||||
|
||||
qbyte *S_Alloc (int size);
|
||||
|
||||
/*
|
||||
================
|
||||
ResampleSfx
|
||||
================
|
||||
*/
|
||||
void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, qbyte *data)
|
||||
{
|
||||
int outcount;
|
||||
int srcsample;
|
||||
float stepscale;
|
||||
int i;
|
||||
int sample, fracstep;
|
||||
unsigned int samplefrac;
|
||||
sfxcache_t *sc;
|
||||
|
||||
sc = Cache_Check (&sfx->cache);
|
||||
if (!sc)
|
||||
return;
|
||||
|
||||
stepscale = (float)inrate / snd_speed; // this is usually 0.5, 1, or 2
|
||||
|
||||
outcount = sc->length / stepscale;
|
||||
sc->length = outcount;
|
||||
if (sc->loopstart != -1)
|
||||
sc->loopstart = sc->loopstart / stepscale;
|
||||
|
||||
sc->speed = snd_speed;
|
||||
if (loadas8bit.value)
|
||||
sc->width = 1;
|
||||
else
|
||||
sc->width = inwidth;
|
||||
|
||||
if (sc->stereo)
|
||||
{
|
||||
if (stepscale == 1 && inwidth == 1 && sc->width == 1)
|
||||
{
|
||||
outcount*=2;
|
||||
// fast special case
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
((signed char *)sc->data)[i]
|
||||
= (int)( (unsigned char)(data[i]) - 128);
|
||||
}
|
||||
else if (stepscale == 1 && inwidth == 2 && sc->width == 2)
|
||||
{
|
||||
outcount*=2;
|
||||
// fast special case
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
((short *)sc->data)[i] = LittleShort ( ((short *)data)[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
// general case
|
||||
samplefrac = 0;
|
||||
fracstep = stepscale*256;
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
{
|
||||
srcsample = samplefrac >> 8;
|
||||
samplefrac += fracstep;
|
||||
if (inwidth == 2)
|
||||
sample = LittleShort ( ((short *)data)[(srcsample<<1)] );
|
||||
else
|
||||
sample = (int)( (unsigned char)(data[(srcsample<<1)]) - 128) << 8;
|
||||
if (sc->width == 2)
|
||||
((short *)sc->data)[i<<1] = sample;
|
||||
else
|
||||
((signed char *)sc->data)[i<<1] = sample >> 8;
|
||||
|
||||
// srcsample = samplefrac >> 8;
|
||||
// samplefrac += fracstep;
|
||||
if (inwidth == 2)
|
||||
sample = LittleShort ( ((short *)data)[(srcsample<<1)+1] );
|
||||
else
|
||||
sample = (int)( (unsigned char)(data[(srcsample<<1)+1]) - 128) << 8;
|
||||
if (sc->width == 2)
|
||||
((short *)sc->data)[(i<<1)+1] = sample;
|
||||
else
|
||||
((signed char *)sc->data)[(i<<1)+1] = sample >> 8;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// resample / decimate to the current source rate
|
||||
|
||||
if (stepscale == 1 && inwidth == 1 && sc->width == 1)
|
||||
{
|
||||
// fast special case
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
((signed char *)sc->data)[i]
|
||||
= (int)( (unsigned char)(data[i]) - 128);
|
||||
}
|
||||
else if (stepscale == 1 && inwidth == 2 && sc->width == 2)
|
||||
{
|
||||
// fast special case
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
((short *)sc->data)[i] = LittleShort ( ((short *)data)[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
// general case
|
||||
samplefrac = 0;
|
||||
fracstep = stepscale*256;
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
{
|
||||
srcsample = samplefrac >> 8;
|
||||
samplefrac += fracstep;
|
||||
if (inwidth == 2)
|
||||
sample = LittleShort ( ((short *)data)[srcsample] );
|
||||
else
|
||||
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
|
||||
if (sc->width == 2)
|
||||
((short *)sc->data)[i] = sample;
|
||||
else
|
||||
((signed char *)sc->data)[i] = sample >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
==============
|
||||
S_LoadSound
|
||||
==============
|
||||
*/
|
||||
#ifdef AVAIL_MP3
|
||||
sfxcache_t *S_LoadMP3Sound (sfx_t *s);
|
||||
#endif
|
||||
sfxcache_t *S_LoadOVSound (sfx_t *s);
|
||||
|
||||
sfxcache_t *S_LoadSound (sfx_t *s)
|
||||
{
|
||||
char namebuffer[256];
|
||||
qbyte *data;
|
||||
wavinfo_t info;
|
||||
int len;
|
||||
float stepscale;
|
||||
sfxcache_t *sc;
|
||||
qbyte stackbuf[1*1024]; // avoid dirtying the cache heap
|
||||
|
||||
// see if still in memory
|
||||
sc = Cache_Check (&s->cache);
|
||||
if (sc)
|
||||
return sc;
|
||||
|
||||
#ifdef AVAIL_OGGVORBIS
|
||||
//ogg vorbis support. The only bit actual code outside snd_ov.c (excluding def for the function call)
|
||||
sc = S_LoadOVSound(s); // try and load a replacement ov instead.
|
||||
if (sc)
|
||||
return sc;
|
||||
#endif
|
||||
|
||||
#ifdef AVAIL_MP3
|
||||
//mp3 support. The only bit actual code outside snd_mp3.c (excluding def for the function call)
|
||||
sc = S_LoadMP3Sound(s); // try and load a replacement mp3 instead.
|
||||
if (sc)
|
||||
return sc;
|
||||
#endif
|
||||
|
||||
|
||||
//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
|
||||
// load it in
|
||||
|
||||
if (*s->name == '*')
|
||||
{
|
||||
Q_strcpy(namebuffer, "players/male/"); //q2
|
||||
Q_strcat(namebuffer, s->name+1); //q2
|
||||
}
|
||||
else if (s->name[0] == '.' && s->name[1] == '.' && s->name[2] == '/')
|
||||
Q_strcpy(namebuffer, s->name+3);
|
||||
else
|
||||
{
|
||||
Q_strcpy(namebuffer, "sound/");
|
||||
Q_strcat(namebuffer, s->name);
|
||||
}
|
||||
|
||||
// Con_Printf ("loading %s\n",namebuffer);
|
||||
|
||||
data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
|
||||
|
||||
if (!data)
|
||||
{
|
||||
//FIXME: check to see if qued for download.
|
||||
Con_Printf ("Couldn't load %s\n", namebuffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = GetWavinfo (s->name, data, com_filesize);
|
||||
if (info.numchannels != 1)
|
||||
{
|
||||
Con_Printf ("%s is a stereo sample\n",s->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stepscale = (float)info.rate / snd_speed;
|
||||
len = info.samples / stepscale;
|
||||
|
||||
len = len * info.width * info.numchannels;
|
||||
|
||||
sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
|
||||
if (!sc)
|
||||
return NULL;
|
||||
|
||||
sc->length = info.samples;
|
||||
sc->loopstart = info.loopstart;
|
||||
sc->speed = info.rate;
|
||||
sc->width = info.width;
|
||||
sc->stereo = 0;//info.numchannels;
|
||||
|
||||
ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
WAV loading
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
qbyte *data_p;
|
||||
qbyte *iff_end;
|
||||
qbyte *last_chunk;
|
||||
qbyte *iff_data;
|
||||
int iff_chunk_len;
|
||||
|
||||
|
||||
short GetLittleShort(void)
|
||||
{
|
||||
short val = 0;
|
||||
val = *data_p;
|
||||
val = val + (*(data_p+1)<<8);
|
||||
data_p += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
int GetLittleLong(void)
|
||||
{
|
||||
int val = 0;
|
||||
val = *data_p;
|
||||
val = val + (*(data_p+1)<<8);
|
||||
val = val + (*(data_p+2)<<16);
|
||||
val = val + (*(data_p+3)<<24);
|
||||
data_p += 4;
|
||||
return val;
|
||||
}
|
||||
|
||||
void FindNextChunk(char *name)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
data_p=last_chunk;
|
||||
data_p += 4;
|
||||
if (data_p >= iff_end)
|
||||
{ // didn't find the chunk
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
iff_chunk_len = GetLittleLong();
|
||||
if (iff_chunk_len < 0)
|
||||
{
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
// if (iff_chunk_len > 1024*1024)
|
||||
// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
|
||||
data_p -= 8;
|
||||
last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
|
||||
if (!Q_strncmp(data_p, name, 4))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void FindChunk(char *name)
|
||||
{
|
||||
last_chunk = iff_data;
|
||||
FindNextChunk (name);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void DumpChunks(void)
|
||||
{
|
||||
char str[5];
|
||||
|
||||
str[4] = 0;
|
||||
data_p=iff_data;
|
||||
do
|
||||
{
|
||||
memcpy (str, data_p, 4);
|
||||
data_p += 4;
|
||||
iff_chunk_len = GetLittleLong();
|
||||
Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
|
||||
data_p += (iff_chunk_len + 1) & ~1;
|
||||
} while (data_p < iff_end);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
============
|
||||
GetWavinfo
|
||||
============
|
||||
*/
|
||||
wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
|
||||
{
|
||||
wavinfo_t info;
|
||||
int i;
|
||||
int format;
|
||||
int samples;
|
||||
|
||||
memset (&info, 0, sizeof(info));
|
||||
|
||||
if (!wav)
|
||||
return info;
|
||||
|
||||
iff_data = wav;
|
||||
iff_end = wav + wavlength;
|
||||
|
||||
// find "RIFF" chunk
|
||||
FindChunk("RIFF");
|
||||
if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4)))
|
||||
{
|
||||
Con_Printf("Missing RIFF/WAVE chunks\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
// get "fmt " chunk
|
||||
iff_data = data_p + 12;
|
||||
// DumpChunks ();
|
||||
|
||||
FindChunk("fmt ");
|
||||
if (!data_p)
|
||||
{
|
||||
Con_Printf("Missing fmt chunk\n");
|
||||
return info;
|
||||
}
|
||||
data_p += 8;
|
||||
format = GetLittleShort();
|
||||
if (format != 1)
|
||||
{
|
||||
Con_Printf("Microsoft PCM format only\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
info.numchannels = GetLittleShort();
|
||||
info.rate = GetLittleLong();
|
||||
data_p += 4+2;
|
||||
info.width = GetLittleShort() / 8;
|
||||
|
||||
// get cue chunk
|
||||
FindChunk("cue ");
|
||||
if (data_p)
|
||||
{
|
||||
data_p += 32;
|
||||
info.loopstart = GetLittleLong();
|
||||
// Con_Printf("loopstart=%d\n", sfx->loopstart);
|
||||
|
||||
// if the next chunk is a LIST chunk, look for a cue length marker
|
||||
FindNextChunk ("LIST");
|
||||
if (data_p)
|
||||
{
|
||||
if (!strncmp (data_p + 28, "mark", 4))
|
||||
{ // this is not a proper parse, but it works with cooledit...
|
||||
data_p += 24;
|
||||
i = GetLittleLong (); // samples in loop
|
||||
info.samples = info.loopstart + i;
|
||||
// Con_Printf("looped length: %i\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
info.loopstart = -1;
|
||||
|
||||
// find data chunk
|
||||
FindChunk("data");
|
||||
if (!data_p)
|
||||
{
|
||||
Con_Printf("Missing data chunk\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
samples = GetLittleLong () / info.width;
|
||||
|
||||
if (info.samples)
|
||||
{
|
||||
if (samples < info.samples)
|
||||
Sys_Error ("Sound %s has a bad loop length", name);
|
||||
}
|
||||
else
|
||||
info.samples = samples;
|
||||
|
||||
info.dataofs = data_p - wav;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,986 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// snd_mix.c -- portable code to mix sounds for snd_dma.c
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
#ifndef NOSOUNDASM
|
||||
#define NOSOUNDASM //since channels per sound card went to 6 (portable_samplegroup_t was changed)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winquake.h"
|
||||
#else
|
||||
#define DWORD unsigned long
|
||||
#endif
|
||||
|
||||
#define PAINTBUFFER_SIZE 2048
|
||||
portable_samplegroup_t paintbuffer[PAINTBUFFER_SIZE];
|
||||
int snd_scaletable[32][256];
|
||||
int *snd_p, snd_vol;
|
||||
short *snd_out;
|
||||
|
||||
void Snd_WriteLinearBlastStereo16 (soundcardinfo_t *sc);
|
||||
|
||||
#if defined(NOSOUNDASM) || !id386
|
||||
void Snd_WriteLinearBlastStereo16 (soundcardinfo_t *sc)
|
||||
{
|
||||
int i, i2;
|
||||
int val;
|
||||
|
||||
for (i=0, i2=0; i<sc->snd_linear_count ; i+=2, i2+=6)
|
||||
{
|
||||
val = (snd_p[i2]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i] = (short)0x8000;
|
||||
else
|
||||
snd_out[i] = val;
|
||||
|
||||
val = (snd_p[i2+1]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+1] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+1] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+1] = val;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void S_TransferStereo16 (soundcardinfo_t *sc, int endtime)
|
||||
{
|
||||
int lpos;
|
||||
int lpaintedtime;
|
||||
DWORD *pbuf;
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
int reps;
|
||||
DWORD dwSize=0,dwSize2=0;
|
||||
DWORD *pbuf2;
|
||||
HRESULT hresult;
|
||||
#endif
|
||||
|
||||
snd_vol = volume.value*256;
|
||||
|
||||
snd_p = (int *) paintbuffer;
|
||||
lpaintedtime = sc->paintedtime;
|
||||
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
if (sc->pDSBuf)
|
||||
{
|
||||
reps = 0;
|
||||
|
||||
while ((hresult = sc->pDSBuf->lpVtbl->Lock(sc->pDSBuf, 0, sc->gSndBufSize, &pbuf, &dwSize,
|
||||
&pbuf2, &dwSize2, 0)) != DS_OK)
|
||||
{
|
||||
if (hresult != DSERR_BUFFERLOST)
|
||||
{
|
||||
Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
|
||||
S_ShutdownCard (sc);
|
||||
SNDDMA_Init (sc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (++reps > 10000)
|
||||
{
|
||||
Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
|
||||
S_ShutdownCard (sc);
|
||||
SNDDMA_Init (sc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pbuf = (DWORD *)sc->sn.buffer;
|
||||
}
|
||||
|
||||
while (lpaintedtime < endtime)
|
||||
{
|
||||
// handle recirculating buffer issues
|
||||
lpos = lpaintedtime % ((sc->sn.samples>>1));
|
||||
|
||||
snd_out = (short *) pbuf + (lpos<<1);
|
||||
|
||||
sc->snd_linear_count = (sc->sn.samples>>1) - lpos;
|
||||
if (lpaintedtime + sc->snd_linear_count > endtime)
|
||||
sc->snd_linear_count = endtime - lpaintedtime;
|
||||
|
||||
sc->snd_linear_count <<= 1;
|
||||
|
||||
// write a linear blast of samples
|
||||
Snd_WriteLinearBlastStereo16 (sc);
|
||||
|
||||
if (sc == sndcardinfo) //only do this for one sound card.
|
||||
Media_RecordAudioFrame(snd_out, sc->snd_linear_count);
|
||||
|
||||
snd_p += sc->snd_linear_count;
|
||||
lpaintedtime += (sc->snd_linear_count>>1);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
if (sc->pDSBuf)
|
||||
sc->pDSBuf->lpVtbl->Unlock(sc->pDSBuf, pbuf, dwSize, NULL, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Snd_WriteLinearBlastStereo16_4Speaker (soundcardinfo_t *sc)
|
||||
{
|
||||
int i, i2;
|
||||
int val;
|
||||
|
||||
for (i=0, i2=0; i<sc->snd_linear_count ; i+=4, i2+=6)
|
||||
{
|
||||
val = (snd_p[i2]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i] = (short)0x8000;
|
||||
else
|
||||
snd_out[i] = val;
|
||||
|
||||
val = (snd_p[i2+1]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+1] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+1] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+1] = val;
|
||||
|
||||
val = (snd_p[i2+2]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+2] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+2] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+2] = val;
|
||||
|
||||
val = (snd_p[i2+3]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+3] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+3] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+3] = val;
|
||||
|
||||
// snd_out[i+0] = rand();
|
||||
// snd_out[i+1] = rand();
|
||||
// snd_out[i+2] = rand();
|
||||
// snd_out[i+3] = rand();
|
||||
}
|
||||
}
|
||||
|
||||
void S_Transfer4Speaker16 (soundcardinfo_t *sc, int endtime)
|
||||
{
|
||||
int lpos;
|
||||
int lpaintedtime;
|
||||
DWORD *pbuf;
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
int reps;
|
||||
DWORD dwSize=0,dwSize2=0;
|
||||
DWORD *pbuf2;
|
||||
HRESULT hresult;
|
||||
#endif
|
||||
|
||||
snd_vol = volume.value*256;
|
||||
|
||||
snd_p = (int *) paintbuffer;
|
||||
lpaintedtime = sc->paintedtime;
|
||||
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
if (sc->pDSBuf)
|
||||
{
|
||||
reps = 0;
|
||||
|
||||
while ((hresult = sc->pDSBuf->lpVtbl->Lock(sc->pDSBuf, 0, sc->gSndBufSize, &pbuf, &dwSize,
|
||||
&pbuf2, &dwSize2, 0)) != DS_OK)
|
||||
{
|
||||
if (hresult != DSERR_BUFFERLOST)
|
||||
{
|
||||
Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
|
||||
S_ShutdownCard (sc);
|
||||
SNDDMA_Init (sc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (++reps > 10000)
|
||||
{
|
||||
Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
|
||||
S_ShutdownCard (sc);
|
||||
SNDDMA_Init (sc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pbuf = (DWORD *)sc->sn.buffer;
|
||||
}
|
||||
|
||||
while (lpaintedtime < endtime)
|
||||
{
|
||||
// handle recirculating buffer issues
|
||||
lpos = lpaintedtime % ((sc->sn.samples>>2));
|
||||
|
||||
snd_out = (short *) pbuf + (lpos<<2);
|
||||
|
||||
sc->snd_linear_count = (sc->sn.samples>>2) - lpos;
|
||||
if (lpaintedtime + sc->snd_linear_count > endtime)
|
||||
sc->snd_linear_count = endtime - lpaintedtime;
|
||||
|
||||
sc->snd_linear_count <<= 2;
|
||||
|
||||
// write a linear blast of samples
|
||||
Snd_WriteLinearBlastStereo16_4Speaker (sc);
|
||||
|
||||
if (sc == sndcardinfo) //only do this for one sound card.
|
||||
Media_RecordAudioFrame(snd_out, sc->snd_linear_count);
|
||||
|
||||
snd_p += sc->snd_linear_count;
|
||||
lpaintedtime += (sc->snd_linear_count>>2);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
if (sc->pDSBuf)
|
||||
sc->pDSBuf->lpVtbl->Unlock(sc->pDSBuf, pbuf, dwSize, NULL, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Snd_WriteLinearBlast6Speaker16 (soundcardinfo_t *sc)
|
||||
{
|
||||
int i;
|
||||
int val;
|
||||
|
||||
for (i=0 ; i<sc->snd_linear_count ; i+=6)
|
||||
{
|
||||
val = (snd_p[i]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i] = (short)0x8000;
|
||||
else
|
||||
snd_out[i] = val;
|
||||
|
||||
val = (snd_p[i+1]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+1] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+1] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+1] = val;
|
||||
|
||||
val = (snd_p[i+2]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+2] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+2] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+2] = val;
|
||||
|
||||
val = (snd_p[i+3]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+3] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+3] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+3] = val;
|
||||
|
||||
val = (snd_p[i+4]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+4] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+4] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+4] = val;
|
||||
|
||||
val = (snd_p[i+5]*snd_vol)>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+5] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+5] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+5] = val;
|
||||
|
||||
#if 0
|
||||
snd_out[i+0] = rand();
|
||||
snd_out[i+1] = rand();
|
||||
snd_out[i+2] = rand();
|
||||
snd_out[i+3] = rand();
|
||||
snd_out[i+4] = rand();
|
||||
snd_out[i+5] = rand();
|
||||
#elif 0
|
||||
snd_out[i+0]=snd_out[i+1]=snd_out[i+2]=snd_out[i+3]=snd_out[i+4]=snd_out[i+5] = rand();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void S_Transfer6Speaker16 (soundcardinfo_t *sc, int endtime)
|
||||
{
|
||||
int lpos;
|
||||
int lpaintedtime;
|
||||
DWORD *pbuf;
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
int reps;
|
||||
DWORD dwSize=0,dwSize2=0;
|
||||
DWORD *pbuf2;
|
||||
HRESULT hresult;
|
||||
#endif
|
||||
|
||||
snd_vol = volume.value*256;
|
||||
|
||||
snd_p = (int *) paintbuffer;
|
||||
lpaintedtime = sc->paintedtime;
|
||||
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
if (sc->pDSBuf)
|
||||
{
|
||||
reps = 0;
|
||||
|
||||
while ((hresult = sc->pDSBuf->lpVtbl->Lock(sc->pDSBuf, 0, sc->gSndBufSize, &pbuf, &dwSize,
|
||||
&pbuf2, &dwSize2, 0)) != DS_OK)
|
||||
{
|
||||
if (hresult != DSERR_BUFFERLOST)
|
||||
{
|
||||
Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
|
||||
S_ShutdownCard (sc);
|
||||
SNDDMA_Init (sc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (++reps > 10000)
|
||||
{
|
||||
Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
|
||||
S_ShutdownCard (sc);
|
||||
SNDDMA_Init (sc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pbuf = (DWORD *)sc->sn.buffer;
|
||||
}
|
||||
|
||||
while (lpaintedtime < endtime)
|
||||
{
|
||||
// handle recirculating buffer issues
|
||||
lpos = (lpaintedtime % ((sc->sn.samples/6)));
|
||||
|
||||
snd_out = (short *) pbuf + (lpos*6);
|
||||
|
||||
sc->snd_linear_count = (sc->sn.samples/6) - lpos;
|
||||
if (lpaintedtime + sc->snd_linear_count > endtime)
|
||||
sc->snd_linear_count = endtime - lpaintedtime;
|
||||
|
||||
sc->snd_linear_count *= 6;
|
||||
|
||||
// write a linear blast of samples
|
||||
Snd_WriteLinearBlast6Speaker16 (sc);
|
||||
|
||||
if (sc == sndcardinfo) //only do this for one sound card.
|
||||
Media_RecordAudioFrame(snd_out, sc->snd_linear_count);
|
||||
|
||||
snd_p += sc->snd_linear_count;
|
||||
lpaintedtime += (sc->snd_linear_count/6);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
if (sc->pDSBuf)
|
||||
sc->pDSBuf->lpVtbl->Unlock(sc->pDSBuf, pbuf, dwSize, NULL, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime)
|
||||
{
|
||||
int out_idx;
|
||||
int count;
|
||||
int out_mask;
|
||||
int *p;
|
||||
int step;
|
||||
int val;
|
||||
int snd_vol;
|
||||
DWORD *pbuf;
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
int reps;
|
||||
DWORD dwSize=0,dwSize2=0;
|
||||
DWORD *pbuf2;
|
||||
HRESULT hresult;
|
||||
#endif
|
||||
|
||||
if (sc->sn.samplebits == 16 && sc->sn.numchannels == 2)
|
||||
{
|
||||
S_TransferStereo16 (sc, endtime);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc->sn.samplebits == 16 && sc->sn.numchannels == 6)
|
||||
{
|
||||
S_Transfer6Speaker16 (sc, endtime);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc->sn.samplebits == 16 && sc->sn.numchannels == 4)
|
||||
{
|
||||
S_Transfer4Speaker16 (sc, endtime);
|
||||
return;
|
||||
}
|
||||
p = (int *) paintbuffer;
|
||||
count = (endtime - sc->paintedtime) * sc->sn.numchannels;
|
||||
out_mask = sc->sn.samples - 1;
|
||||
out_idx = sc->paintedtime * sc->sn.numchannels & out_mask;
|
||||
if (sc->sn.numchannels>2)
|
||||
step = 1;
|
||||
else
|
||||
step = 3 - sc->sn.numchannels;
|
||||
snd_vol = volume.value*256;
|
||||
|
||||
|
||||
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
if (sc->pDSBuf)
|
||||
{
|
||||
reps = 0;
|
||||
|
||||
while ((hresult = sc->pDSBuf->lpVtbl->Lock(sc->pDSBuf, 0, sc->gSndBufSize, &pbuf, &dwSize,
|
||||
&pbuf2,&dwSize2, 0)) != DS_OK)
|
||||
{
|
||||
if (hresult != DSERR_BUFFERLOST)
|
||||
{
|
||||
Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
|
||||
S_ShutdownCard (sc);
|
||||
SNDDMA_Init (sc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (++reps > 10000)
|
||||
{
|
||||
Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
|
||||
S_ShutdownCard (sc);
|
||||
SNDDMA_Init (sc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pbuf = (DWORD *)sc->sn.buffer;
|
||||
}
|
||||
|
||||
if (sc->sn.samplebits == 16)
|
||||
{
|
||||
short *out = (short *) pbuf;
|
||||
while (count--)
|
||||
{
|
||||
val = (*p * snd_vol) >> 8;
|
||||
p+= step;
|
||||
if (val > 0x7fff)
|
||||
val = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
val = (short)0x8000;
|
||||
out[out_idx] = val;
|
||||
out_idx = (out_idx + 1) & out_mask;
|
||||
}
|
||||
}
|
||||
else if (sc->sn.samplebits == 8)
|
||||
{
|
||||
unsigned char *out = (unsigned char *) pbuf;
|
||||
while (count--)
|
||||
{
|
||||
val = (*p * snd_vol) >> 8;
|
||||
p+= step;
|
||||
if (val > 0x7fff)
|
||||
val = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
val = (short)0x8000;
|
||||
out[out_idx] = (val>>8) + 128;
|
||||
out_idx = (out_idx + 1) & out_mask;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(NODIRECTX)
|
||||
if (sc->pDSBuf) {
|
||||
DWORD dwNewpos, dwWrite;
|
||||
int il = sc->paintedtime;
|
||||
int ir = endtime - sc->paintedtime;
|
||||
|
||||
ir += il;
|
||||
|
||||
sc->pDSBuf->lpVtbl->Unlock(sc->pDSBuf, pbuf, dwSize, NULL, 0);
|
||||
|
||||
sc->pDSBuf->lpVtbl->GetCurrentPosition(sc->pDSBuf, &dwNewpos, &dwWrite);
|
||||
|
||||
// if ((dwNewpos >= il) && (dwNewpos <= ir))
|
||||
// Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
CHANNEL MIXING
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
|
||||
void SND_PaintChannelFrom8Duel (channel_t *ch, sfxcache_t *sc, int endtime);
|
||||
void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
|
||||
void SND_PaintChannelFrom8_4Speaker (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelFrom16_4Speaker (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelFrom8_6Speaker (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelFrom16_6Speaker (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelFrom8Stereo (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelFrom16Stereo (channel_t *ch, sfxcache_t *sc, int count);
|
||||
|
||||
void S_PaintChannels(soundcardinfo_t *sc, int endtime)
|
||||
{
|
||||
int i, j;
|
||||
int end;
|
||||
channel_t *ch;
|
||||
sfxcache_t *scache;
|
||||
sfx_t *s;
|
||||
int ltime, count;
|
||||
|
||||
// sc->rawstart += sc->paintedtime - sc->oldpaintedtime;
|
||||
// sc->oldpaintedtime = sc->paintedtime;
|
||||
|
||||
while (sc->paintedtime < endtime)
|
||||
{
|
||||
// if paintbuffer is smaller than DMA buffer
|
||||
end = endtime;
|
||||
if (endtime - sc->paintedtime > PAINTBUFFER_SIZE)
|
||||
end = sc->paintedtime + PAINTBUFFER_SIZE;
|
||||
|
||||
// clear the paint buffer
|
||||
Q_memset(paintbuffer, 0, (end - sc->paintedtime) * sizeof(portable_samplegroup_t));
|
||||
|
||||
// paint in the channels.
|
||||
ch = sc->channel;
|
||||
for (i=0; i<sc->total_chans ; i++, ch++)
|
||||
{
|
||||
if (!ch->sfx)
|
||||
continue;
|
||||
if (!ch->vol[0] && !ch->vol[1] && !ch->vol[2] && !ch->vol[3] && !ch->vol[4] && !ch->vol[5])
|
||||
continue;
|
||||
scache = S_LoadSound (ch->sfx);
|
||||
if (!scache)
|
||||
continue;
|
||||
|
||||
if (ch->pos > scache->length) //cache was flushed and gamedir changed.
|
||||
{
|
||||
ch->pos = scache->length;
|
||||
ch->end = scache->length;
|
||||
}
|
||||
|
||||
|
||||
ltime = sc->paintedtime;
|
||||
|
||||
if (ch->sfx->decoder)
|
||||
{
|
||||
soundcardinfo_t *sndc;
|
||||
#define qmax(x, y) (x>y)?(x):(y)
|
||||
ch->sfx->decoder->decodemore(ch->sfx,
|
||||
ch->pos + end-ltime+1000);
|
||||
//ch->pos + qmax(end-ltime+1000, 1000)); //try to exceed by a little.
|
||||
scache = S_LoadSound (ch->sfx);
|
||||
if (!scache)
|
||||
continue;
|
||||
|
||||
for (sndc = sndcardinfo; sndc; sndc=sndc->next)
|
||||
{
|
||||
for (j = 0; j < sndc->total_chans; j++)
|
||||
if (sndc->channel[j].sfx == ch->sfx) //extend all of these.
|
||||
ch->end = ltime + (scache->length - ch->pos);
|
||||
}
|
||||
}
|
||||
|
||||
while (ltime < end)
|
||||
{ // paint up to end
|
||||
if (ch->end < end)
|
||||
count = ch->end - ltime;
|
||||
else
|
||||
count = end - ltime;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
if (ch->pos < 0) //delay the sound a little
|
||||
{
|
||||
if (count > -ch->pos)
|
||||
count = -ch->pos;
|
||||
ltime += count;
|
||||
ch->pos += count;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*dmw having fun
|
||||
int uw;
|
||||
int oldpos = ch->pos;
|
||||
int vol = ch->vol[0];
|
||||
int rvol = ch->vol[1];
|
||||
int end = ch->end;
|
||||
ch->vol[1]=0;
|
||||
ch->vol[0]/=2;
|
||||
for (uw = 0; uw < 5; uw++)
|
||||
{
|
||||
*/
|
||||
if (scache->width == 1)
|
||||
{
|
||||
if (scache->stereo)
|
||||
SND_PaintChannelFrom8Stereo(ch, scache, count);
|
||||
else if (sc->sn.numchannels == 6)
|
||||
SND_PaintChannelFrom8_6Speaker(ch, scache, count);
|
||||
else if (sc->sn.numchannels == 4)
|
||||
SND_PaintChannelFrom8_4Speaker(ch, scache, count);
|
||||
else
|
||||
SND_PaintChannelFrom8(ch, scache, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (scache->stereo)
|
||||
SND_PaintChannelFrom16Stereo(ch, scache, count);
|
||||
else if (sc->sn.numchannels == 6)
|
||||
SND_PaintChannelFrom16_6Speaker(ch, scache, count);
|
||||
else if (sc->sn.numchannels == 4)
|
||||
SND_PaintChannelFrom16_4Speaker(ch, scache, count);
|
||||
else
|
||||
SND_PaintChannelFrom16(ch, scache, count);
|
||||
}
|
||||
/* lots of fun
|
||||
// ch->vol[0]*=-1;
|
||||
ch->vol[1]=0;
|
||||
ch->vol[0]/=1.3;
|
||||
ch->pos=oldpos-cursndcard->sn.speed*uw*0.06;
|
||||
if (ch->pos >= sc->length || ch->pos < 0)
|
||||
break;
|
||||
|
||||
}
|
||||
ch->vol[0] = vol;
|
||||
ch->vol[1] = rvol;
|
||||
ch->pos = oldpos+count;
|
||||
*/
|
||||
ltime += count;
|
||||
}
|
||||
|
||||
// if at end of loop, restart
|
||||
if (ltime >= ch->end)
|
||||
{
|
||||
if (scache->loopstart >= 0)
|
||||
{
|
||||
ch->pos = scache->loopstart;
|
||||
ch->end = ltime + scache->length - ch->pos;
|
||||
if (!scache->length)
|
||||
{
|
||||
scache->loopstart=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // channel just stopped
|
||||
s = ch->sfx;
|
||||
ch->sfx = NULL;
|
||||
if (s->decoder)
|
||||
{
|
||||
if (!S_IsPlayingSomewhere(s))
|
||||
s->decoder->abort(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// transfer out according to DMA format
|
||||
S_TransferPaintBuffer(sc, end);
|
||||
sc->paintedtime = end;
|
||||
}
|
||||
}
|
||||
|
||||
void SND_InitScaletable (void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i=0 ; i<32 ; i++)
|
||||
for (j=0 ; j<256 ; j++)
|
||||
snd_scaletable[i][j] = ((signed char)j) * i * 8;
|
||||
}
|
||||
|
||||
|
||||
#if defined(NOSOUNDASM) || !id386
|
||||
|
||||
void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
int data;
|
||||
int *lscale, *rscale;
|
||||
unsigned char *sfx;
|
||||
int i;
|
||||
|
||||
if (ch->vol[0] > 255)
|
||||
ch->vol[0] = 255;
|
||||
if (ch->vol[1] > 255)
|
||||
ch->vol[1] = 255;
|
||||
|
||||
|
||||
lscale = snd_scaletable[ch->vol[0] >> 3];
|
||||
rscale = snd_scaletable[ch->vol[1] >> 3];
|
||||
sfx = (signed char *)sc->data + ch->pos;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
data = sfx[i];
|
||||
paintbuffer[i].s[0] += lscale[data];
|
||||
paintbuffer[i].s[1] += rscale[data];
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
void SND_PaintChannelFrom8Duel (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
int *lscale, *rscale;
|
||||
unsigned char *sfx1, *sfx2;
|
||||
int i;
|
||||
|
||||
if (ch->vol[0] > 255)
|
||||
ch->vol[0] = 255;
|
||||
if (ch->vol[1] > 255)
|
||||
ch->vol[1] = 255;
|
||||
|
||||
|
||||
lscale = snd_scaletable[ch->vol[0] >> 3];
|
||||
rscale = snd_scaletable[ch->vol[1] >> 3];
|
||||
i = ch->pos - ch->delay[0];
|
||||
if (i < 0) i = 0;
|
||||
sfx1 = (signed char *)sc->data + i;
|
||||
i = ch->pos - ch->delay[1];
|
||||
if (i < 0) i = 0;
|
||||
sfx2 = (signed char *)sc->data + i;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
paintbuffer[i].s[0] += lscale[sfx1[i]];
|
||||
paintbuffer[i].s[1] += rscale[sfx2[i]];
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
#endif // !id386
|
||||
|
||||
void SND_PaintChannelFrom8Stereo (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
// int data;
|
||||
int *lscale, *rscale;
|
||||
unsigned char *sfx;
|
||||
int i;
|
||||
|
||||
if (ch->vol[0] > 255)
|
||||
ch->vol[0] = 255;
|
||||
if (ch->vol[1] > 255)
|
||||
ch->vol[1] = 255;
|
||||
|
||||
|
||||
lscale = snd_scaletable[ch->vol[0] >> 3];
|
||||
rscale = snd_scaletable[ch->vol[1] >> 3];
|
||||
sfx = (signed char *)sc->data + ch->pos;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
paintbuffer[i].s[0] += lscale[sfx[(i<<1)]];
|
||||
paintbuffer[i].s[1] += rscale[sfx[(i<<1)+1]];
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
void SND_PaintChannelFrom8_4Speaker (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
int *scale0, *scale1, *scale2, *scale3;
|
||||
unsigned char *sfx;
|
||||
int i;
|
||||
|
||||
if (ch->vol[0] > 255)
|
||||
ch->vol[0] = 255;
|
||||
if (ch->vol[1] > 255)
|
||||
ch->vol[1] = 255;
|
||||
if (ch->vol[2] > 255)
|
||||
ch->vol[2] = 255;
|
||||
if (ch->vol[3] > 255)
|
||||
ch->vol[3] = 255;
|
||||
|
||||
scale0 = snd_scaletable[ch->vol[0] >> 3];
|
||||
scale1 = snd_scaletable[ch->vol[1] >> 3];
|
||||
scale2 = snd_scaletable[ch->vol[2] >> 3];
|
||||
scale3 = snd_scaletable[ch->vol[3] >> 3];
|
||||
sfx = (signed char *)sc->data + ch->pos;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
paintbuffer[i].s[0] += scale0[sfx[i]];
|
||||
paintbuffer[i].s[1] += scale1[sfx[i]];
|
||||
paintbuffer[i].s[2] += scale2[sfx[i]];
|
||||
paintbuffer[i].s[3] += scale3[sfx[i]];
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
void SND_PaintChannelFrom8_6Speaker (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
int *scale0, *scale1, *scale2, *scale3, *scale4, *scale5;
|
||||
unsigned char *sfx;
|
||||
int i;
|
||||
|
||||
if (ch->vol[0] > 255)
|
||||
ch->vol[0] = 255;
|
||||
if (ch->vol[1] > 255)
|
||||
ch->vol[1] = 255;
|
||||
if (ch->vol[2] > 255)
|
||||
ch->vol[2] = 255;
|
||||
if (ch->vol[3] > 255)
|
||||
ch->vol[3] = 255;
|
||||
if (ch->vol[4] > 255)
|
||||
ch->vol[4] = 255;
|
||||
if (ch->vol[5] > 255)
|
||||
ch->vol[5] = 255;
|
||||
|
||||
scale0 = snd_scaletable[ch->vol[0] >> 3];
|
||||
scale1 = snd_scaletable[ch->vol[1] >> 3];
|
||||
scale2 = snd_scaletable[ch->vol[2] >> 3];
|
||||
scale3 = snd_scaletable[ch->vol[3] >> 3];
|
||||
scale4 = snd_scaletable[ch->vol[4] >> 3];
|
||||
scale5 = snd_scaletable[ch->vol[5] >> 3];
|
||||
sfx = (signed char *)sc->data + ch->pos;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
paintbuffer[i].s[0] += scale0[sfx[i]];
|
||||
paintbuffer[i].s[1] += scale1[sfx[i]];
|
||||
paintbuffer[i].s[2] += scale2[sfx[i]];
|
||||
paintbuffer[i].s[3] += scale3[sfx[i]];
|
||||
paintbuffer[i].s[4] += scale4[sfx[i]];
|
||||
paintbuffer[i].s[5] += scale5[sfx[i]];
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
int data;
|
||||
int left, right;
|
||||
int leftvol, rightvol;
|
||||
signed short *sfx;
|
||||
int i;
|
||||
|
||||
leftvol = ch->vol[0];
|
||||
rightvol = ch->vol[1];
|
||||
sfx = (signed short *)sc->data + ch->pos;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
data = sfx[i];
|
||||
left = (data * leftvol) >> 8;
|
||||
right = (data * rightvol) >> 8;
|
||||
paintbuffer[i].s[0] += left;
|
||||
paintbuffer[i].s[1] += right;
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
void SND_PaintChannelFrom16Stereo (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
int leftvol, rightvol;
|
||||
signed short *sfx;
|
||||
int i;
|
||||
|
||||
leftvol = ch->vol[0];
|
||||
rightvol = ch->vol[1];
|
||||
sfx = (signed short *)sc->data + ch->pos*2;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
paintbuffer[i].s[0] += (*sfx++ * leftvol) >> 8;
|
||||
paintbuffer[i].s[1] += (*sfx++ * rightvol) >> 8;
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
void SND_PaintChannelFrom16_6Speaker (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
int vol[6];
|
||||
signed short *sfx;
|
||||
int i;
|
||||
|
||||
vol[0] = ch->vol[0];
|
||||
vol[1] = ch->vol[1];
|
||||
vol[2] = ch->vol[2];
|
||||
vol[3] = ch->vol[3];
|
||||
vol[4] = ch->vol[4];
|
||||
vol[5] = ch->vol[5];
|
||||
sfx = (signed short *)sc->data + ch->pos;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
paintbuffer[i].s[0] += (sfx[i] * vol[0]) >> 8;
|
||||
paintbuffer[i].s[1] += (sfx[i] * vol[1]) >> 8;
|
||||
paintbuffer[i].s[2] += (sfx[i] * vol[2]) >> 8;
|
||||
paintbuffer[i].s[3] += (sfx[i] * vol[3]) >> 8;
|
||||
paintbuffer[i].s[4] += (sfx[i] * vol[4]) >> 8;
|
||||
paintbuffer[i].s[5] += (sfx[i] * vol[5]) >> 8;
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
void SND_PaintChannelFrom16_4Speaker (channel_t *ch, sfxcache_t *sc, int count)
|
||||
{
|
||||
int vol[4];
|
||||
signed short *sfx;
|
||||
int i;
|
||||
|
||||
vol[0] = ch->vol[0];
|
||||
vol[1] = ch->vol[1];
|
||||
vol[2] = ch->vol[2];
|
||||
vol[3] = ch->vol[3];
|
||||
sfx = (signed short *)sc->data + ch->pos;
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
paintbuffer[i].s[0] += (sfx[i] * vol[0]) >> 8;
|
||||
paintbuffer[i].s[1] += (sfx[i] * vol[1]) >> 8;
|
||||
paintbuffer[i].s[2] += (sfx[i] * vol[2]) >> 8;
|
||||
paintbuffer[i].s[3] += (sfx[i] * vol[3]) >> 8;
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// snd_mixa.s
|
||||
// x86 assembly-language sound code
|
||||
//
|
||||
|
||||
#include "asm_i386.h"
|
||||
#include "quakeasm.h"
|
||||
|
||||
#define NOSOUNDASM //we no longer use any of this code, now that we have multiple sound cards.
|
||||
|
||||
#if !defined(NOSOUNDASM) && id386
|
||||
|
||||
.text
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 8-bit sound-mixing code
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define ch 4+16
|
||||
#define sc 8+16
|
||||
#define count 12+16
|
||||
|
||||
.globl C(SND_PaintChannelFrom8)
|
||||
C(SND_PaintChannelFrom8):
|
||||
pushl %esi // preserve register variables
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
pushl %ebp
|
||||
|
||||
// int data;
|
||||
// short *lscale, *rscale;
|
||||
// unsigned char *sfx;
|
||||
// int i;
|
||||
|
||||
movl ch(%esp),%ebx
|
||||
movl sc(%esp),%esi
|
||||
|
||||
// if (ch->leftvol > 255)
|
||||
// ch->leftvol = 255;
|
||||
// if (ch->rightvol > 255)
|
||||
// ch->rightvol = 255;
|
||||
movl ch_vol(%ebx),%eax
|
||||
movl ch_vol(%ebx),%edx
|
||||
cmpl $255,%eax
|
||||
jna LLeftSet
|
||||
movl $255,%eax
|
||||
LLeftSet:
|
||||
cmpl $255,%edx
|
||||
jna LRightSet
|
||||
movl $255,%edx
|
||||
LRightSet:
|
||||
|
||||
// lscale = snd_scaletable[ch->leftvol >> 3];
|
||||
// rscale = snd_scaletable[ch->rightvol >> 3];
|
||||
// sfx = (signed char *)sc->data + ch->pos;
|
||||
// ch->pos += count;
|
||||
andl $0xF8,%eax
|
||||
addl $(sfxc_data),%esi
|
||||
andl $0xF8,%edx
|
||||
movl ch_pos(%ebx),%edi
|
||||
movl count(%esp),%ecx
|
||||
addl %edi,%esi
|
||||
shll $7,%eax
|
||||
addl %ecx,%edi
|
||||
shll $7,%edx
|
||||
movl %edi,ch_pos(%ebx)
|
||||
addl $(C(snd_scaletable)),%eax
|
||||
addl $(C(snd_scaletable)),%edx
|
||||
subl %ebx,%ebx
|
||||
movb -1(%esi,%ecx,1),%bl
|
||||
|
||||
testl $1,%ecx
|
||||
jz LMix8Loop
|
||||
|
||||
movl (%eax,%ebx,4),%edi
|
||||
movl (%edx,%ebx,4),%ebp
|
||||
addl C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi
|
||||
addl C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp
|
||||
movl %edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size)
|
||||
movl %ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size)
|
||||
movb -2(%esi,%ecx,1),%bl
|
||||
|
||||
decl %ecx
|
||||
jz LDone
|
||||
|
||||
// for (i=0 ; i<count ; i++)
|
||||
// {
|
||||
LMix8Loop:
|
||||
|
||||
// data = sfx[i];
|
||||
// paintbuffer[i].left += lscale[data];
|
||||
// paintbuffer[i].right += rscale[data];
|
||||
movl (%eax,%ebx,4),%edi
|
||||
movl (%edx,%ebx,4),%ebp
|
||||
addl C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi
|
||||
addl C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp
|
||||
movb -2(%esi,%ecx,1),%bl
|
||||
movl %edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size)
|
||||
movl %ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size)
|
||||
|
||||
movl (%eax,%ebx,4),%edi
|
||||
movl (%edx,%ebx,4),%ebp
|
||||
movb -3(%esi,%ecx,1),%bl
|
||||
addl C(paintbuffer)+psp_left-psp_size*2(,%ecx,psp_size),%edi
|
||||
addl C(paintbuffer)+psp_right-psp_size*2(,%ecx,psp_size),%ebp
|
||||
movl %edi,C(paintbuffer)+psp_left-psp_size*2(,%ecx,psp_size)
|
||||
movl %ebp,C(paintbuffer)+psp_right-psp_size*2(,%ecx,psp_size)
|
||||
|
||||
// }
|
||||
subl $2,%ecx
|
||||
jnz LMix8Loop
|
||||
|
||||
LDone:
|
||||
popl %ebp
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
|
||||
ret
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Transfer of stereo buffer to 16-bit DMA buffer code
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
//runs backwards.
|
||||
//otherwise same algorthm as c
|
||||
//i = ecx
|
||||
|
||||
.globl C(Snd_WriteLinearBlastStereo16)
|
||||
C(Snd_WriteLinearBlastStereo16):
|
||||
pushl %esi // preserve register variables
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
|
||||
// int i;
|
||||
// int val;
|
||||
movl C(cursndcard),%ecx // DMW was snd_linear_count
|
||||
movl C(snd_p),%ebx
|
||||
movl C(snd_vol),%esi
|
||||
movl C(snd_out),%edi
|
||||
|
||||
movl 0(%ecx),%ecx // DMW dereference pointer (I think)
|
||||
|
||||
// for (i=0 ; i<snd_linear_count ; i+=2)
|
||||
// {
|
||||
LWLBLoopTop:
|
||||
|
||||
// val = (snd_p[i]*snd_vol)>>8;
|
||||
// if (val > 0x7fff)
|
||||
// snd_out[i] = 0x7fff;
|
||||
// else if (val < (short)0x8000)
|
||||
// snd_out[i] = (short)0x8000;
|
||||
// else
|
||||
// snd_out[i] = val;
|
||||
movl -8(%ebx,%ecx,4),%eax
|
||||
imull %esi,%eax
|
||||
sarl $8,%eax
|
||||
cmpl $0x7FFF,%eax
|
||||
jg LClampHigh
|
||||
cmpl $0xFFFF8000,%eax
|
||||
jnl LClampDone
|
||||
movl $0xFFFF8000,%eax
|
||||
jmp LClampDone
|
||||
LClampHigh:
|
||||
movl $0x7FFF,%eax
|
||||
LClampDone:
|
||||
|
||||
// val = (snd_p[i+1]*snd_vol)>>8;
|
||||
// if (val > 0x7fff)
|
||||
// snd_out[i+1] = 0x7fff;
|
||||
// else if (val < (short)0x8000)
|
||||
// snd_out[i+1] = (short)0x8000;
|
||||
// else
|
||||
// snd_out[i+1] = val;
|
||||
movl -4(%ebx,%ecx,4),%edx
|
||||
imull %esi,%edx
|
||||
sarl $8,%edx
|
||||
cmpl $0x7FFF,%edx
|
||||
jg LClampHigh2
|
||||
cmpl $0xFFFF8000,%edx
|
||||
jnl LClampDone2
|
||||
movl $0xFFFF8000,%edx
|
||||
jmp LClampDone2
|
||||
LClampHigh2:
|
||||
movl $0x7FFF,%edx
|
||||
LClampDone2:
|
||||
shll $16,%edx
|
||||
andl $0xFFFF,%eax
|
||||
orl %eax,%edx
|
||||
movl %edx,-4(%edi,%ecx,2)
|
||||
|
||||
// }
|
||||
subl $2,%ecx
|
||||
jnz LWLBLoopTop
|
||||
|
||||
// snd_p += snd_linear_count;
|
||||
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
|
||||
ret
|
||||
|
||||
|
||||
#endif // id386
|
|
@ -0,0 +1,497 @@
|
|||
//source file by david walton, derived from minimad.c
|
||||
//modified slightly to use new library functions instead for single threaded asyncronous mp3 sound.
|
||||
//in Quake!
|
||||
|
||||
//Be aware that MP3s are patented and thus not GPLable. This file is an interface to madlib which contains the decoder.
|
||||
//This file is excluded from the main source tree because of this, and madlib is not distributed - in binary or source form.
|
||||
//The GPL disallows distribution of patented software. You may reactive, but do not distribute binaries.
|
||||
|
||||
//Really madlib should come with the exception of the mp3 patent.
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
#ifdef AVAIL_MP3
|
||||
|
||||
#include "winquake.h"
|
||||
#undef channels
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define inline _inline
|
||||
#endif
|
||||
|
||||
//the problem with this is that we store the entire decoded file in memory.
|
||||
//this takes a lot of mem.
|
||||
|
||||
//uses madlib
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* mad - MPEG audio decoder
|
||||
* Copyright (C) 2000-2001 Robert Leslie
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
# include "../../mp3/libmad/mad.h"
|
||||
|
||||
|
||||
/*
|
||||
* This is perhaps the simplest example use of the MAD high-level API.
|
||||
* Standard input is mapped into memory via mmap(), then the high-level API
|
||||
* is invoked with three callbacks: input, output, and error. The output
|
||||
* callback converts MAD's high-resolution PCM samples to 16 bits, then
|
||||
* writes them to standard output in little-endian, stereo-interleaved
|
||||
* format.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This is a private message structure. A generic pointer to this structure
|
||||
* is passed to each of the callback functions. Put here any data you need
|
||||
* to access from within the callbacks.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned char *start;
|
||||
unsigned long length;
|
||||
qboolean failed;
|
||||
|
||||
sfxcache_t mp3sc;
|
||||
char *mp3aswavdata;
|
||||
int mp3aswavpos;
|
||||
int mp3aswavbuflen;
|
||||
|
||||
struct mad_decoder decoder;
|
||||
|
||||
sfx_t *s;
|
||||
} decoderbuffer_t;
|
||||
|
||||
int mymad_run(struct mad_decoder *decoder);
|
||||
int mymad_reset(struct mad_decoder *decoder);
|
||||
void mymad_finish(struct mad_decoder *decoder);
|
||||
int startdecode(unsigned char *start, unsigned long length, decoderbuffer_t *buffer);
|
||||
|
||||
#define BUFFERSIZEINC (2*1024*1024)
|
||||
|
||||
int DecodeSomeMP3(sfx_t *s, int minlength);
|
||||
byte *COM_LoadFile (char *path, int usehunk);
|
||||
int MP3_decode(unsigned char *start, unsigned long length, decoderbuffer_t *buffer);
|
||||
void CancelDecoder(sfx_t *s);
|
||||
sfxcache_t *S_LoadMP3Sound (sfx_t *s)
|
||||
{
|
||||
char namebuffer[MAX_OSPATH];
|
||||
char *name;
|
||||
decoderbuffer_t *buffer;
|
||||
|
||||
char *data;
|
||||
qboolean telluser;
|
||||
int len;
|
||||
|
||||
name = s->name;
|
||||
|
||||
if (name[0] == '#')
|
||||
strcpy(namebuffer, &name[1]);
|
||||
else
|
||||
sprintf (namebuffer, "sound/%s", name);
|
||||
|
||||
len = strlen(namebuffer);
|
||||
telluser = strcmp(namebuffer+len-4, ".wav");
|
||||
if (!telluser)
|
||||
strcpy(namebuffer+len-4, ".mp3");
|
||||
|
||||
//try opening from a quake path
|
||||
data = COM_LoadFile(namebuffer, 5);
|
||||
if (!data)
|
||||
{//if that didn't work, try opening direct from exe - this is media after all.
|
||||
FILE *f;
|
||||
|
||||
if (!telluser)
|
||||
return NULL; //never go out of the quake path for a wav replacement.
|
||||
#ifndef _WIN32
|
||||
char unixname[128];
|
||||
if (name[1] == ':' && name[2] == '\\') //convert from windows to a suitable alternative.
|
||||
{
|
||||
sprintf(unixname, "/mnt/%c/%s", name[0]-'A'+'a', name+3);
|
||||
name = unixname;
|
||||
while (*name)
|
||||
{
|
||||
if (*name == '\\')
|
||||
*name = '/';
|
||||
name++;
|
||||
}
|
||||
name = unixname;
|
||||
}
|
||||
#endif
|
||||
if ((f = fopen(name, "rb")))
|
||||
{
|
||||
com_filesize = COM_filelength(f);
|
||||
data = BZ_Malloc(com_filesize);
|
||||
fread(data, 1, com_filesize, f);
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_SafePrintf ("Couldn't load %s\n", namebuffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->decoder)
|
||||
s->decoder = Z_Malloc(sizeof(decoderbuffer_t) + sizeof(sfxdecode_t));
|
||||
buffer = (decoderbuffer_t*)(s->decoder+1);
|
||||
|
||||
buffer->mp3aswavpos=0;
|
||||
buffer->mp3sc.length=0;
|
||||
buffer->s = s;
|
||||
s->decoder->buf = buffer;
|
||||
s->decoder->decodemore = DecodeSomeMP3;
|
||||
s->decoder->abort = CancelDecoder;
|
||||
|
||||
if (!startdecode(data, com_filesize, buffer))
|
||||
{
|
||||
if (buffer->mp3aswavdata)
|
||||
{
|
||||
BZ_Free(buffer->mp3aswavdata);
|
||||
|
||||
buffer->mp3aswavdata=NULL;
|
||||
}
|
||||
Con_SafePrintf ("Couldn't load %s - corrupt.\n", namebuffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->decoder->decodemore(s, 100);
|
||||
|
||||
s->cache.fake=true;
|
||||
return buffer->s->cache.data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is the input callback. The purpose of this callback is to (re)fill
|
||||
* the stream buffer which is to be decoded. In this example, an entire file
|
||||
* has been mapped into memory, so we just call mad_stream_buffer() with the
|
||||
* address and length of the mapping. When this callback is called a second
|
||||
* time, we are finished decoding.
|
||||
*/
|
||||
|
||||
static
|
||||
enum mad_flow input(void *data,
|
||||
struct mad_stream *stream)
|
||||
{
|
||||
decoderbuffer_t *buffer = data;
|
||||
|
||||
if (!buffer->length)
|
||||
return MAD_FLOW_STOP;
|
||||
|
||||
mad_stream_buffer(stream, buffer->start, buffer->length);
|
||||
|
||||
buffer->length = 0;
|
||||
|
||||
return MAD_FLOW_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following utility routine performs simple rounding, clipping, and
|
||||
* scaling of MAD's high-resolution samples down to 16 bits. It does not
|
||||
* perform any dithering or noise shaping, which would be recommended to
|
||||
* obtain any exceptional audio quality. It is therefore not recommended to
|
||||
* use this routine if high-quality output is desired.
|
||||
*/
|
||||
|
||||
static inline
|
||||
signed int scale(mad_fixed_t sample)
|
||||
{
|
||||
/* round */
|
||||
sample += (1L << (MAD_F_FRACBITS - 16));
|
||||
|
||||
/* clip */
|
||||
if (sample >= MAD_F_ONE)
|
||||
sample = MAD_F_ONE - 1;
|
||||
else if (sample < -MAD_F_ONE)
|
||||
sample = -MAD_F_ONE;
|
||||
|
||||
/* quantize */
|
||||
return sample >> (MAD_F_FRACBITS + 1 - 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the output callback function. It is called after each frame of
|
||||
* MPEG audio data has been completely decoded. The purpose of this callback
|
||||
* is to output (or play) the decoded PCM audio.
|
||||
*/
|
||||
|
||||
static
|
||||
enum mad_flow output(void *data,
|
||||
struct mad_header const *header,
|
||||
struct mad_pcm *pcm)
|
||||
{
|
||||
decoderbuffer_t *buffer = data;
|
||||
sfxcache_t *cache;
|
||||
|
||||
unsigned int nchannels, nsamples;
|
||||
mad_fixed_t const *left_ch, *right_ch;
|
||||
|
||||
char *outpos;
|
||||
signed int sample;
|
||||
float speedfactor;
|
||||
|
||||
speedfactor = (float)snd_speed/buffer->mp3sc.speed;
|
||||
|
||||
/* pcm->samplerate contains the sampling frequency */
|
||||
|
||||
nchannels = pcm->channels;
|
||||
nsamples = pcm->length*speedfactor;
|
||||
left_ch = pcm->samples[0];
|
||||
right_ch = pcm->samples[1];
|
||||
|
||||
if (buffer->mp3aswavpos + nsamples*nchannels*sizeof(short) > buffer->mp3aswavbuflen || !buffer->mp3aswavdata)
|
||||
{
|
||||
int newsize = buffer->mp3aswavpos + nsamples*nchannels*sizeof(short) + BUFFERSIZEINC+sizeof(sfxcache_t);
|
||||
char *newbuf = BZ_Malloc(newsize);
|
||||
if (!newbuf)
|
||||
return MAD_FLOW_STOP; //damn and blast!
|
||||
|
||||
if (buffer->mp3aswavdata) //if we had an old buffer, fill the new one and free the old
|
||||
{
|
||||
// memset(newbuf, 0, newsize);
|
||||
memcpy(newbuf, buffer->mp3aswavdata, buffer->mp3aswavpos+sizeof(sfxcache_t));
|
||||
// newbuf[newsize] = '\0';
|
||||
BZ_Free(buffer->mp3aswavdata);
|
||||
}
|
||||
buffer->mp3aswavdata = newbuf;
|
||||
buffer->mp3aswavbuflen = newsize;
|
||||
|
||||
buffer->s->cache.data = buffer->mp3aswavdata;
|
||||
}
|
||||
|
||||
cache = (sfxcache_t *)buffer->mp3aswavdata;
|
||||
outpos = buffer->mp3aswavdata+sizeof(sfxcache_t) + buffer->mp3aswavpos;
|
||||
|
||||
if (nchannels == 1)
|
||||
{
|
||||
if (speedfactor==1) //fast
|
||||
{
|
||||
while (nsamples--)
|
||||
{
|
||||
sample = scale(*left_ch++);
|
||||
*outpos++ = ((sample >> 0) & 0xff);
|
||||
*outpos++ = ((sample >> 8) & 0xff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int src=0;
|
||||
int pos=0;
|
||||
|
||||
while (pos < nsamples)
|
||||
{
|
||||
src = pos/speedfactor;
|
||||
sample = scale(left_ch[src]);
|
||||
*outpos++ = (((sample >> 0) & 0xff));
|
||||
*outpos++ = (((sample >> 8) & 0xff));
|
||||
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
cache->stereo = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (speedfactor==1) //fast
|
||||
{
|
||||
while (nsamples--)
|
||||
{ //merge channels?
|
||||
sample = scale(*left_ch++);
|
||||
*outpos++ = (((sample >> 0) & 0xff));
|
||||
*outpos++ = (((sample >> 8) & 0xff));
|
||||
|
||||
sample = scale(*right_ch++)/2;
|
||||
*outpos++ = (((sample >> 0) & 0xff));
|
||||
*outpos++ = (((sample >> 8) & 0xff));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int src=0;
|
||||
int pos=0;
|
||||
|
||||
while (pos < nsamples)
|
||||
{
|
||||
src = pos/speedfactor;
|
||||
sample = scale(left_ch[src]);
|
||||
*outpos++ = (((sample >> 0) & 0xff));
|
||||
*outpos++ = (((sample >> 8) & 0xff));
|
||||
|
||||
sample = scale(right_ch[src]);
|
||||
*outpos++ = (((sample >> 0) & 0xff));
|
||||
*outpos++ = (((sample >> 8) & 0xff));
|
||||
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
cache->stereo = 1;
|
||||
}
|
||||
|
||||
buffer->mp3aswavpos += pcm->length*speedfactor*sizeof(short)*nchannels;
|
||||
buffer->mp3sc.length+= pcm->length*speedfactor;
|
||||
|
||||
cache->speed = snd_speed;
|
||||
cache->length = buffer->s->decoder->decodedlen = buffer->mp3sc.length;
|
||||
cache->loopstart = -1;//buffer->mp3sc.loopstart;
|
||||
cache->width = buffer->mp3sc.width;
|
||||
|
||||
return MAD_FLOW_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the error callback function. It is called whenever a decoding
|
||||
* error occurs. The error is indicated by stream->error; the list of
|
||||
* possible MAD_ERROR_* errors can be found in the mad.h (or
|
||||
* libmad/stream.h) header file.
|
||||
*/
|
||||
|
||||
static
|
||||
enum mad_flow error(void *data,
|
||||
struct mad_stream *stream,
|
||||
struct mad_frame *frame)
|
||||
{
|
||||
decoderbuffer_t *buffer = data;
|
||||
|
||||
if (stream->error == 257)
|
||||
return MAD_FLOW_IGNORE;
|
||||
|
||||
if (developer.value)
|
||||
Con_SafePrintf("MP3Error: decoding error 0x%04x (%s) at byte offset %u\n",
|
||||
stream->error, mad_stream_errorstr(stream),
|
||||
stream->this_frame - buffer->start);
|
||||
|
||||
// buffer->failed = true;
|
||||
|
||||
return MAD_FLOW_IGNORE;
|
||||
}
|
||||
|
||||
static enum mad_flow header(void *data,
|
||||
struct mad_header const *header)
|
||||
{
|
||||
decoderbuffer_t *buffer = data;
|
||||
|
||||
buffer->mp3sc.speed = header->samplerate;
|
||||
buffer->mp3sc.width = 2;
|
||||
return MAD_FLOW_CONTINUE;
|
||||
}
|
||||
|
||||
void CancelDecoder(sfx_t *s)
|
||||
{
|
||||
decoderbuffer_t *dec = s->decoder->buf;
|
||||
|
||||
mymad_finish(&dec->decoder);
|
||||
mad_decoder_finish(&dec->decoder);
|
||||
|
||||
s->cache.fake = false; //give it a true cache now, and hope that we don't need to free it while it's still playing.
|
||||
s->cache.data=NULL;
|
||||
|
||||
BZ_Free(dec->mp3aswavdata);
|
||||
if (dec->start)
|
||||
BZ_Free(dec->start);
|
||||
|
||||
Z_Free(s->decoder);
|
||||
s->decoder = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the function called by main() above to perform all the
|
||||
* decoding. It instantiates a decoder object and configures it with the
|
||||
* input, output, and error callback functions above. A single call to
|
||||
* mad_decoder_run() continues until a callback function returns
|
||||
* MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
|
||||
* signal an error).
|
||||
*/
|
||||
|
||||
int DecodeSomeMP3(sfx_t *s, int minlength)
|
||||
{
|
||||
decoderbuffer_t *dec = s->decoder->buf;
|
||||
|
||||
// int oldlen;
|
||||
|
||||
if (!dec->start)
|
||||
return 1;
|
||||
|
||||
while(dec->mp3sc.length < minlength)
|
||||
{
|
||||
if (!mymad_run(&dec->decoder) || dec->failed)
|
||||
{
|
||||
if (dec->mp3aswavbuflen>441000)//10 secs at highest quality
|
||||
{ //big fat heffers of mp3s are kept like this and are flushed when they finish playing fully.
|
||||
BZ_Free(dec->start);
|
||||
dec->start = NULL;
|
||||
}
|
||||
else
|
||||
{ //small mp3 files are now treated like wavs
|
||||
void *newmem;
|
||||
mymad_finish(&dec->decoder);
|
||||
mad_decoder_finish(&dec->decoder);
|
||||
|
||||
s->cache.fake = false; //give it a true cache now, and hope that we don't need to free it while it's still playing.
|
||||
s->cache.data=NULL;
|
||||
newmem = Cache_Alloc(&s->cache, dec->mp3aswavbuflen+sizeof(sfxcache_t), s->name);
|
||||
if (dec->mp3aswavdata)
|
||||
{
|
||||
memcpy(newmem, dec->mp3aswavdata, dec->mp3aswavbuflen+sizeof(sfxcache_t));
|
||||
BZ_Free(dec->mp3aswavdata);
|
||||
}
|
||||
BZ_Free(dec->start);
|
||||
|
||||
Z_Free(s->decoder);
|
||||
s->decoder = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mymad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode);
|
||||
static
|
||||
int startdecode(unsigned char *start, unsigned long length, decoderbuffer_t *buffer)
|
||||
{
|
||||
/* initialize our private message structure */
|
||||
|
||||
buffer->start = start;
|
||||
buffer->length = length;
|
||||
buffer->failed = false;
|
||||
|
||||
/* configure input, output, and error functions */
|
||||
|
||||
mad_decoder_init(&buffer->decoder, buffer,
|
||||
input, header, 0 /* filter */, output,
|
||||
error, 0 /* message */);
|
||||
|
||||
/* start decoding */
|
||||
|
||||
mymad_reset(&buffer->decoder);
|
||||
|
||||
if (buffer->failed)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
#ifdef AVAIL_OGGVORBIS
|
||||
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
|
||||
|
||||
#if defined(_WIN32) && !defined(STATICVORBIS)
|
||||
#define WINDOWSDYNAMICLINK
|
||||
#include <windows.h>
|
||||
HINSTANCE oggvorbislibrary;
|
||||
#endif
|
||||
|
||||
int (*p_ov_open_callbacks) (void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks);
|
||||
int (*p_ov_clear)(OggVorbis_File *vf);
|
||||
vorbis_info *(*p_ov_info)(OggVorbis_File *vf,int link);
|
||||
vorbis_comment *(*p_ov_comment) (OggVorbis_File *vf,int link);
|
||||
ogg_int64_t (*p_ov_pcm_total)(OggVorbis_File *vf,int i);
|
||||
long (*p_ov_read)(OggVorbis_File *vf,char *buffer,int length,
|
||||
int bigendianp,int word,int sgned,int *bitstream);
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned char *start; //file positions
|
||||
unsigned long length;
|
||||
unsigned long pos;
|
||||
|
||||
qboolean failed;
|
||||
|
||||
sfxcache_t mediasc;
|
||||
char *mediaaswavdata;
|
||||
int mediaaswavpos;
|
||||
int mediaaswavbuflen;
|
||||
|
||||
OggVorbis_File vf;
|
||||
|
||||
sfx_t *s;
|
||||
} ovdecoderbuffer_t;
|
||||
|
||||
int OV_DecodeSome(sfx_t *s, int minlength);
|
||||
void OV_CancelDecoder(sfx_t *s);
|
||||
int OV_StartDecode(unsigned char *start, unsigned long length, ovdecoderbuffer_t *buffer);
|
||||
|
||||
qbyte *COM_LoadFile (char *path, int usehunk);
|
||||
|
||||
sfxcache_t *S_LoadOVSound (sfx_t *s)
|
||||
{
|
||||
char namebuffer[MAX_OSPATH];
|
||||
char *name;
|
||||
ovdecoderbuffer_t *buffer;
|
||||
FILE *f;
|
||||
|
||||
char *data;
|
||||
qboolean telluser;
|
||||
int len;
|
||||
|
||||
name = s->name;
|
||||
|
||||
if (name[0] == '#')
|
||||
strcpy(namebuffer, &name[1]);
|
||||
else
|
||||
sprintf (namebuffer, "sound/%s", name);
|
||||
|
||||
len = strlen(namebuffer);
|
||||
telluser = strcmp(namebuffer+len-4, ".wav");
|
||||
if (!telluser)
|
||||
strcpy(namebuffer+len-4, ".ogg");
|
||||
|
||||
//try opening from a quake path
|
||||
data = COM_LoadMallocFile(namebuffer);
|
||||
if (!data)
|
||||
{//if that didn't work, try opening direct from exe - this is media after all.
|
||||
|
||||
if (!telluser)
|
||||
return NULL; //never go out of the quake path for a wav replacement.
|
||||
#ifndef _WIN32
|
||||
char unixname[128];
|
||||
if (name[1] == ':' && name[2] == '\\') //convert from windows to a suitable alternative.
|
||||
{
|
||||
sprintf(unixname, "/mnt/%c/%s", name[0]-'A'+'a', name+3);
|
||||
name = unixname;
|
||||
while (*name)
|
||||
{
|
||||
if (*name == '\\')
|
||||
*name = '/';
|
||||
name++;
|
||||
}
|
||||
name = unixname;
|
||||
}
|
||||
#endif
|
||||
if ((f = fopen(name, "rb")))
|
||||
{
|
||||
com_filesize = COM_filelength(f);
|
||||
data = BZ_Malloc(com_filesize);
|
||||
fread(data, 1, com_filesize, f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_SafePrintf ("Couldn't load %s\n", namebuffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->decoder)
|
||||
s->decoder = Z_Malloc(sizeof(ovdecoderbuffer_t) + sizeof(sfxdecode_t));
|
||||
buffer = (ovdecoderbuffer_t*)(s->decoder+1);
|
||||
|
||||
buffer->mediaaswavpos=0;
|
||||
buffer->mediasc.length=0;
|
||||
buffer->s = s;
|
||||
s->decoder->buf = buffer;
|
||||
s->decoder->decodemore = OV_DecodeSome;
|
||||
s->decoder->abort = OV_CancelDecoder;
|
||||
|
||||
if (!OV_StartDecode(data, com_filesize, buffer))
|
||||
{
|
||||
if (buffer->mediaaswavdata)
|
||||
{
|
||||
free(buffer->mediaaswavdata);
|
||||
|
||||
buffer->mediaaswavdata=NULL;
|
||||
}
|
||||
Z_Free(s->decoder);
|
||||
s->decoder=NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->decoder->decodemore(s, 100);
|
||||
|
||||
s->cache.fake=true;
|
||||
return buffer->s->cache.data;
|
||||
}
|
||||
|
||||
int OV_DecodeSome(sfx_t *s, int minlength)
|
||||
{
|
||||
ovdecoderbuffer_t *dec = s->decoder->buf;
|
||||
int bytesread;
|
||||
|
||||
// while ((bytesread = ov_read(&dec->vf, s->cache+dec->, int length, int bigendianp, int word, int sgned, int *bitstream))
|
||||
// ov_read(
|
||||
return 0;
|
||||
}
|
||||
void OV_CancelDecoder(sfx_t *s)
|
||||
{
|
||||
ovdecoderbuffer_t *buffer;
|
||||
buffer = s->decoder->buf;
|
||||
p_ov_clear (&buffer->vf);
|
||||
}
|
||||
|
||||
static size_t read_func (void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
ovdecoderbuffer_t *buffer = datasource;
|
||||
int spare = buffer->length - buffer->pos;
|
||||
|
||||
if (size*nmemb > spare)
|
||||
nmemb = spare / size;
|
||||
memcpy(ptr, &buffer->start[buffer->pos], size*nmemb);
|
||||
buffer->pos += size*nmemb;
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
static int seek_func (void *datasource, ogg_int64_t offset, int whence)
|
||||
{
|
||||
ovdecoderbuffer_t *buffer = datasource;
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
buffer->pos = offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
buffer->pos = buffer->length+offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
buffer->pos+=offset;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int close_func (void *datasource)
|
||||
{
|
||||
ovdecoderbuffer_t *buffer = datasource;
|
||||
free(buffer->start);
|
||||
buffer->start=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long tell_func (void *datasource)
|
||||
{
|
||||
ovdecoderbuffer_t *buffer = datasource;
|
||||
return buffer->pos;
|
||||
}
|
||||
static ov_callbacks callbacks = {
|
||||
read_func,
|
||||
seek_func,
|
||||
close_func,
|
||||
tell_func,
|
||||
};
|
||||
qboolean OV_StartDecode(unsigned char *start, unsigned long length, ovdecoderbuffer_t *buffer)
|
||||
{
|
||||
#ifdef WINDOWSDYNAMICLINK
|
||||
if (!oggvorbislibrary)
|
||||
{
|
||||
oggvorbislibrary = LoadLibrary("vorbisfile.dll");
|
||||
if (!oggvorbislibrary)
|
||||
{
|
||||
Con_Printf("Couldn't load DLL: \"vorbisfile.dll\".\n");
|
||||
return false;
|
||||
}
|
||||
p_ov_open_callbacks = (void *)GetProcAddress(oggvorbislibrary, "ov_open_callbacks");
|
||||
p_ov_comment = (void *)GetProcAddress(oggvorbislibrary, "ov_comment");
|
||||
p_ov_pcm_total = (void *)GetProcAddress(oggvorbislibrary, "ov_pcm_total");
|
||||
p_ov_clear = (void *)GetProcAddress(oggvorbislibrary, "ov_clear");
|
||||
p_ov_info = (void *)GetProcAddress(oggvorbislibrary, "ov_info");
|
||||
}
|
||||
#else
|
||||
p_ov_open_callbacks = ov_open_callbacks;
|
||||
#endif
|
||||
|
||||
buffer->start = start;
|
||||
buffer->length = length;
|
||||
buffer->pos = 0;
|
||||
if (p_ov_open_callbacks(buffer, &buffer->vf, NULL, 0, callbacks))
|
||||
{
|
||||
Con_Printf("Input does not appear to be an Ogg bitstream.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Throw the comments plus a few lines about the bitstream we're
|
||||
decoding */
|
||||
{
|
||||
char **ptr=p_ov_comment(&buffer->vf,-1)->user_comments;
|
||||
vorbis_info *vi=p_ov_info(&buffer->vf,-1);
|
||||
while(*ptr){
|
||||
Con_Printf("%s\n",*ptr);
|
||||
++ptr;
|
||||
}
|
||||
Con_Printf("\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate);
|
||||
Con_Printf("\nDecoded length: %ld samples\n",
|
||||
(long)p_ov_pcm_total(&buffer->vf,-1));
|
||||
Con_Printf("Encoded by: %s\n\n",p_ov_comment(&buffer->vf,-1)->vendor);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sound.h -- client sound i/o functions
|
||||
|
||||
#ifndef __SOUND__
|
||||
#define __SOUND__
|
||||
|
||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||
#define MAXSOUNDCHANNELS 6 //on a per device basis
|
||||
|
||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||
struct sfx_s;
|
||||
/*typedef struct
|
||||
{
|
||||
int left;
|
||||
int right;
|
||||
} portable_samplepair_t;
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int s[MAXSOUNDCHANNELS];
|
||||
} portable_samplegroup_t;
|
||||
|
||||
typedef struct {
|
||||
int decodedlen;
|
||||
int (*decodemore) (struct sfx_s *sfx, int length); //retrurn true when done.
|
||||
void (*abort) (struct sfx_s *sfx); //it's not playing elsewhere. free entirly
|
||||
void *buf;
|
||||
} sfxdecode_t;
|
||||
|
||||
typedef struct sfx_s
|
||||
{
|
||||
char name[MAX_OSPATH];
|
||||
cache_user_t cache;
|
||||
sfxdecode_t *decoder;
|
||||
} sfx_t;
|
||||
|
||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||
typedef struct sfxcache_s
|
||||
{
|
||||
int length;
|
||||
int loopstart;
|
||||
int speed;
|
||||
int width;
|
||||
int stereo;
|
||||
qbyte data[1]; // variable sized
|
||||
} sfxcache_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean gamealive;
|
||||
qboolean soundalive;
|
||||
qboolean splitbuffer;
|
||||
int numchannels;
|
||||
int samples; // mono samples in buffer
|
||||
int submission_chunk; // don't mix less than this #
|
||||
int samplepos; // in mono samples
|
||||
int samplebits;
|
||||
int speed;
|
||||
unsigned char *buffer;
|
||||
} dma_t;
|
||||
|
||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||
typedef struct
|
||||
{
|
||||
sfx_t *sfx; // sfx number
|
||||
int vol[MAXSOUNDCHANNELS]; // 0-255 volume
|
||||
int delay[MAXSOUNDCHANNELS];
|
||||
int end; // end time in global paintsamples
|
||||
int pos; // sample position in sfx
|
||||
int looping; // where to loop, -1 = no looping
|
||||
int entnum; // to allow overriding a specific sound
|
||||
int entchannel; //int audio_fd
|
||||
vec3_t origin; // origin of sound effect
|
||||
vec_t dist_mult; // distance multiplier (attenuation/clipK)
|
||||
int master_vol; // 0-255 master volume
|
||||
} channel_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int rate;
|
||||
int width;
|
||||
int numchannels;
|
||||
int loopstart;
|
||||
int samples;
|
||||
int dataofs; // chunk starts this many bytes from file start
|
||||
} wavinfo_t;
|
||||
|
||||
struct soundcardinfo_s;
|
||||
typedef struct soundcardinfo_s soundcardinfo_t;
|
||||
|
||||
void S_Init (void);
|
||||
void S_Startup (void);
|
||||
void S_Shutdown (void);
|
||||
void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation);
|
||||
void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation);
|
||||
void S_StopSound (int entnum, int entchannel);
|
||||
void S_StopAllSounds(qboolean clear);
|
||||
void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
|
||||
void S_ExtraUpdate (void);
|
||||
|
||||
sfx_t *S_PrecacheSound (char *sample);
|
||||
void S_TouchSound (char *sample);
|
||||
void S_ClearPrecache (void);
|
||||
void S_BeginPrecaching (void);
|
||||
void S_EndPrecaching (void);
|
||||
|
||||
void S_ClearBuffer (soundcardinfo_t *sc);
|
||||
|
||||
void S_PaintChannels(soundcardinfo_t *sc, int endtime);
|
||||
void S_InitPaintChannels (soundcardinfo_t *sc);
|
||||
|
||||
void S_ShutdownCard (soundcardinfo_t *sc);
|
||||
void S_StopSoundCard (soundcardinfo_t *sc, int entnum, int entchannel);
|
||||
|
||||
qboolean S_IsPlayingSomewhere(sfx_t *s);
|
||||
void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, qbyte *data);
|
||||
|
||||
// picks a channel based on priorities, empty slots, number of channels
|
||||
channel_t *SND_PickChannel(soundcardinfo_t *sc, int entnum, int entchannel);
|
||||
|
||||
// spatializes a channel
|
||||
void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch);
|
||||
|
||||
// initializes cycling through a DMA buffer and returns information on it
|
||||
int SNDDMA_Init(soundcardinfo_t *sc);
|
||||
|
||||
// gets the current DMA position
|
||||
int SNDDMA_GetDMAPos(soundcardinfo_t *sc);
|
||||
|
||||
// shutdown the DMA xfer.
|
||||
void SNDDMA_Shutdown(soundcardinfo_t *sc);
|
||||
|
||||
// restart entire sound subsystem
|
||||
void S_Restart_f (void);
|
||||
|
||||
//plays streaming audio
|
||||
void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, int width);
|
||||
|
||||
//tells the audio capture routines to grab a bit more and send it to voice chat server.
|
||||
void S_UpdateCapture(void);
|
||||
void CLVC_Poll (void);
|
||||
|
||||
void SNDVC_MicInput(qbyte *buffer, int samples, int freq, int width);
|
||||
|
||||
// ====================================================================
|
||||
// User-setable variables
|
||||
// ====================================================================
|
||||
|
||||
#define MAX_CHANNELS 128
|
||||
#define MAX_DYNAMIC_CHANNELS 8
|
||||
|
||||
|
||||
//
|
||||
// Fake dma is a synchronous faking of the DMA progress used for
|
||||
// isolating performance in the renderer. The fakedma_updates is
|
||||
// number of times S_Update() is called per second.
|
||||
//
|
||||
|
||||
extern int snd_speed;
|
||||
|
||||
extern qboolean fakedma;
|
||||
extern int fakedma_updates;
|
||||
extern vec3_t listener_origin;
|
||||
extern vec3_t listener_forward;
|
||||
extern vec3_t listener_right;
|
||||
extern vec3_t listener_up;
|
||||
extern vec_t sound_nominal_clip_dist;
|
||||
|
||||
extern cvar_t loadas8bit;
|
||||
extern cvar_t bgmvolume;
|
||||
extern cvar_t volume;
|
||||
extern cvar_t snd_capture;
|
||||
|
||||
extern qboolean snd_initialized;
|
||||
extern qboolean snd_multipledevices;
|
||||
|
||||
extern int snd_blocked;
|
||||
|
||||
void S_LocalSound (char *s);
|
||||
sfxcache_t *S_LoadSound (sfx_t *s);
|
||||
|
||||
wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength);
|
||||
|
||||
void SND_InitScaletable (void);
|
||||
void SNDDMA_Submit(soundcardinfo_t *sc);
|
||||
|
||||
void S_AmbientOff (void);
|
||||
void S_AmbientOn (void);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
|
||||
struct soundcardinfo_s { //windows has one defined AFTER directsound
|
||||
float dist[MAX_CHANNELS];
|
||||
float pitch[MAX_CHANNELS];
|
||||
float yaw[MAX_CHANNELS];
|
||||
|
||||
char name[256];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
qboolean snd_isdirect;
|
||||
qboolean snd_iswave;
|
||||
|
||||
int paintedtime;
|
||||
int oldsamplepos;
|
||||
int buffers;
|
||||
|
||||
qboolean dsound_init;
|
||||
qboolean wav_init;
|
||||
|
||||
volatile dma_t sn;
|
||||
|
||||
int snd_linear_count;
|
||||
|
||||
int snd_sent;
|
||||
int snd_completed;
|
||||
|
||||
int audio_fd;
|
||||
|
||||
channel_t channel[MAX_CHANNELS];
|
||||
int total_chans;
|
||||
|
||||
int rawend;
|
||||
int rawstart;
|
||||
|
||||
struct soundcardinfo_s *next;
|
||||
};
|
||||
#endif
|
||||
|
||||
extern soundcardinfo_t *sndcardinfo;
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// spritegn.h: header file for sprite generation program
|
||||
//
|
||||
|
||||
// **********************************************************
|
||||
// * This file must be identical in the spritegen directory *
|
||||
// * and in the Quake directory, because it's used to *
|
||||
// * pass data from one to the other via .spr files. *
|
||||
// **********************************************************
|
||||
|
||||
//-------------------------------------------------------
|
||||
// This program generates .spr sprite package files.
|
||||
// The format of the files is as follows:
|
||||
//
|
||||
// dsprite_t file header structure
|
||||
// <repeat dsprite_t.numframes times>
|
||||
// <if spritegroup, repeat dspritegroup_t.numframes times>
|
||||
// dspriteframe_t frame header structure
|
||||
// sprite bitmap
|
||||
// <else (single sprite frame)>
|
||||
// dspriteframe_t frame header structure
|
||||
// sprite bitmap
|
||||
// <endrepeat>
|
||||
//-------------------------------------------------------
|
||||
|
||||
#ifdef INCLUDELIBS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "scriplib.h"
|
||||
#include "dictlib.h"
|
||||
#include "trilib.h"
|
||||
#include "lbmlib.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
#endif
|
||||
|
||||
#define SPRITE_VERSION 1
|
||||
#define SPRITE32_VERSION 32
|
||||
|
||||
// must match definition in modelgen.h
|
||||
#ifndef SYNCTYPE_T
|
||||
#define SYNCTYPE_T
|
||||
typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
|
||||
#endif
|
||||
|
||||
// TODO: shorten these?
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
int type;
|
||||
float boundingradius;
|
||||
int width;
|
||||
int height;
|
||||
int numframes;
|
||||
float beamlength;
|
||||
synctype_t synctype;
|
||||
} dsprite_t;
|
||||
|
||||
#define SPR_VP_PARALLEL_UPRIGHT 0
|
||||
#define SPR_FACING_UPRIGHT 1
|
||||
#define SPR_VP_PARALLEL 2
|
||||
#define SPR_ORIENTED 3
|
||||
#define SPR_VP_PARALLEL_ORIENTED 4
|
||||
|
||||
typedef struct {
|
||||
int origin[2];
|
||||
int width;
|
||||
int height;
|
||||
} dspriteframe_t;
|
||||
|
||||
typedef struct {
|
||||
int numframes;
|
||||
} dspritegroup_t;
|
||||
|
||||
typedef struct {
|
||||
float interval;
|
||||
} dspriteinterval_t;
|
||||
|
||||
typedef enum { SPR_SINGLE=0, SPR_GROUP, SPR_ANGLED } spriteframetype_t;
|
||||
|
||||
typedef struct {
|
||||
spriteframetype_t type;
|
||||
} dspriteframetype_t;
|
||||
|
||||
#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I')
|
||||
// little-endian "IDSP"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define MAX_SKINNAME 64
|
||||
#define IDSPRITE2HEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
|
||||
// little-endian "IDS2"
|
||||
#define SPRITE2_VERSION 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
int origin_x, origin_y; // raster coordinates inside pic
|
||||
char name[MAX_SKINNAME]; // name of pcx file
|
||||
} dmd2sprframe_t;
|
||||
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
int numframes;
|
||||
dmd2sprframe_t frames[1]; // variable sized
|
||||
} dmd2sprite_t;
|
||||
|
||||
|
|
@ -0,0 +1,938 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sys_win.h
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
#include "resource.h"
|
||||
#include "errno.h"
|
||||
#include "fcntl.h"
|
||||
#include <limits.h>
|
||||
#include <conio.h>
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
|
||||
#ifdef NODIRECTX
|
||||
#define DDActive 0
|
||||
#endif
|
||||
|
||||
|
||||
#define MINIMUM_WIN_MEMORY 0x0800000
|
||||
#define MAXIMUM_WIN_MEMORY 0x1000000
|
||||
|
||||
#define PAUSE_SLEEP 50 // sleep time on pause or minimization
|
||||
#define NOT_FOCUS_SLEEP 20 // sleep time when not focus
|
||||
|
||||
int starttime;
|
||||
qboolean ActiveApp, Minimized;
|
||||
qboolean WinNT;
|
||||
|
||||
HWND hwnd_dialog; // startup dialog box
|
||||
|
||||
static HANDLE hinput, houtput;
|
||||
|
||||
HANDLE qwclsemaphore;
|
||||
|
||||
static HANDLE tevent;
|
||||
|
||||
void Sys_InitFloatTime (void);
|
||||
|
||||
void VARGS MaskExceptions (void);
|
||||
void Sys_PopFPCW (void);
|
||||
void Sys_PushFPCW_SetHigh (void);
|
||||
|
||||
void VARGS Sys_DebugLog(char *file, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
static char data[1024];
|
||||
int fd;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
_vsnprintf(data, sizeof(data)-1, fmt, argptr);
|
||||
va_end(argptr);
|
||||
fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
|
||||
write(fd, data, strlen(data));
|
||||
close(fd);
|
||||
};
|
||||
|
||||
int *debug;
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE IO
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_filelength
|
||||
================
|
||||
*/
|
||||
int Sys_filelength (FILE *f)
|
||||
{
|
||||
int pos;
|
||||
int end;
|
||||
|
||||
pos = ftell (f);
|
||||
fseek (f, 0, SEEK_END);
|
||||
end = ftell (f);
|
||||
fseek (f, pos, SEEK_SET);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
int Sys_FileTime (char *path)
|
||||
{
|
||||
FILE *f;
|
||||
int t=0, retval;
|
||||
|
||||
if (qrenderer)
|
||||
t = VID_ForceUnlockedAndReturnState ();
|
||||
|
||||
f = fopen(path, "rb");
|
||||
|
||||
if (f)
|
||||
{
|
||||
fclose(f);
|
||||
retval = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
if (qrenderer)
|
||||
VID_ForceLockState (t);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Sys_mkdir (char *path)
|
||||
{
|
||||
_mkdir (path);
|
||||
}
|
||||
|
||||
qboolean Sys_remove (char *path)
|
||||
{
|
||||
remove (path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Sys_EnumerateFiles (char *gpath, char *match, int (*func)(char *, int, void *), void *parm)
|
||||
{
|
||||
HANDLE r;
|
||||
WIN32_FIND_DATA fd;
|
||||
char apath[MAX_OSPATH];
|
||||
char file[MAX_OSPATH];
|
||||
char *s;
|
||||
int go;
|
||||
strcpy(apath, match);
|
||||
// sprintf(apath, "%s%s", gpath, match);
|
||||
for (s = apath+strlen(apath)-1; s>= apath; s--)
|
||||
{
|
||||
if (*s == '/')
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
*s = '\0';
|
||||
|
||||
|
||||
if (gpath)
|
||||
sprintf(file, "%s/%s", gpath, match);
|
||||
else
|
||||
strcpy(file, match);
|
||||
r = FindFirstFile(file, &fd);
|
||||
if (r==(HANDLE)-1)
|
||||
return 1;
|
||||
go = true;
|
||||
do
|
||||
{
|
||||
if (*fd.cFileName == '.');
|
||||
else if (fd.dwFileAttributes != 16) //is a directory
|
||||
{
|
||||
sprintf(file, "%s%s", apath, fd.cFileName);
|
||||
go = func(file, fd.nFileSizeLow, parm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(file, "%s%s/", apath, fd.cFileName);
|
||||
go = func(file, fd.nFileSizeLow, parm);
|
||||
}
|
||||
}
|
||||
while(FindNextFile(r, &fd) && go);
|
||||
FindClose(r);
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
SYSTEM IO
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_MakeCodeWriteable
|
||||
================
|
||||
*/
|
||||
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
|
||||
{
|
||||
DWORD flOldProtect;
|
||||
|
||||
//@@@ copy on write or just read-write?
|
||||
if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect))
|
||||
Sys_Error("Protection change failed\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Init
|
||||
================
|
||||
*/
|
||||
void Sys_Init (void)
|
||||
{
|
||||
// LARGE_INTEGER PerformanceFreq;
|
||||
// unsigned int lowpart, highpart;
|
||||
OSVERSIONINFO vinfo;
|
||||
/*
|
||||
#ifndef SERVERONLY
|
||||
#ifndef CLIENTONLY
|
||||
if (!isDedicated)
|
||||
#endif
|
||||
{
|
||||
// allocate a named semaphore on the client so the
|
||||
// front end can tell if it is alive
|
||||
|
||||
// mutex will fail if semephore allready exists
|
||||
qwclsemaphore = CreateMutex(
|
||||
NULL, // Security attributes
|
||||
0, // owner
|
||||
"qwcl"); // Semaphore name
|
||||
// if (!qwclsemaphore)
|
||||
// Sys_Error ("QWCL is already running on this system");
|
||||
CloseHandle (qwclsemaphore);
|
||||
|
||||
qwclsemaphore = CreateSemaphore(
|
||||
NULL, // Security attributes
|
||||
0, // Initial count
|
||||
1, // Maximum count
|
||||
"qwcl"); // Semaphore name
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
MaskExceptions ();
|
||||
Sys_SetFPCW ();
|
||||
|
||||
#if 0
|
||||
if (!QueryPerformanceFrequency (&PerformanceFreq))
|
||||
Sys_Error ("No hardware timer available");
|
||||
|
||||
// get 32 out of the 64 time bits such that we have around
|
||||
// 1 microsecond resolution
|
||||
lowpart = (unsigned int)PerformanceFreq.LowPart;
|
||||
highpart = (unsigned int)PerformanceFreq.HighPart;
|
||||
lowshift = 0;
|
||||
|
||||
while (highpart || (lowpart > 2000000.0))
|
||||
{
|
||||
lowshift++;
|
||||
lowpart >>= 1;
|
||||
lowpart |= (highpart & 1) << 31;
|
||||
highpart >>= 1;
|
||||
}
|
||||
|
||||
pfreq = 1.0 / (double)lowpart;
|
||||
|
||||
Sys_InitFloatTime ();
|
||||
#endif
|
||||
|
||||
// make sure the timer is high precision, otherwise
|
||||
// NT gets 18ms resolution
|
||||
timeBeginPeriod( 1 );
|
||||
|
||||
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
|
||||
|
||||
if (!GetVersionEx (&vinfo))
|
||||
Sys_Error ("Couldn't get OS info");
|
||||
|
||||
if ((vinfo.dwMajorVersion < 4) ||
|
||||
(vinfo.dwPlatformId == VER_PLATFORM_WIN32s))
|
||||
{
|
||||
Sys_Error ("QuakeWorld requires at least Win95 or NT 4.0");
|
||||
}
|
||||
|
||||
if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||
WinNT = true;
|
||||
else
|
||||
WinNT = false;
|
||||
}
|
||||
|
||||
|
||||
void VARGS Sys_Error (const char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
//, text2[1024];
|
||||
// DWORD dummy;
|
||||
|
||||
va_start (argptr, error);
|
||||
_vsnprintf (text, sizeof(text)-1, error, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Host_Shutdown ();
|
||||
|
||||
MessageBox(NULL, text, "Error", 0);
|
||||
|
||||
#ifndef SERVERONLY
|
||||
CloseHandle (qwclsemaphore);
|
||||
#endif
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void VARGS Sys_Printf (char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
DWORD dummy;
|
||||
|
||||
if (!houtput)
|
||||
return;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
_vsnprintf (text, sizeof(text)-1, fmt, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
WriteFile (houtput, text, strlen(text), &dummy, NULL);
|
||||
}
|
||||
|
||||
void Sys_Quit (void)
|
||||
{
|
||||
if (VID_ForceUnlockedAndReturnState)
|
||||
VID_ForceUnlockedAndReturnState ();
|
||||
|
||||
Host_Shutdown();
|
||||
|
||||
#ifndef SERVERONLY
|
||||
if (tevent)
|
||||
CloseHandle (tevent);
|
||||
|
||||
if (qwclsemaphore)
|
||||
CloseHandle (qwclsemaphore);
|
||||
#endif
|
||||
|
||||
/* Yeah, right, just wishful thinking.
|
||||
#ifdef _DEBUG
|
||||
if (Z_Allocated())
|
||||
MessageBox(0, "Some memory was left allocated", "Mem was left", 0);
|
||||
#endif
|
||||
*/
|
||||
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
================
|
||||
Sys_DoubleTime
|
||||
================
|
||||
*/
|
||||
double Sys_DoubleTime (void)
|
||||
{
|
||||
static int sametimecount;
|
||||
static unsigned int oldtime;
|
||||
static int first = 1;
|
||||
LARGE_INTEGER PerformanceCount;
|
||||
unsigned int temp, t2;
|
||||
double time;
|
||||
|
||||
Sys_PushFPCW_SetHigh ();
|
||||
|
||||
QueryPerformanceCounter (&PerformanceCount);
|
||||
|
||||
temp = ((unsigned int)PerformanceCount.LowPart >> lowshift) |
|
||||
((unsigned int)PerformanceCount.HighPart << (32 - lowshift));
|
||||
|
||||
if (first)
|
||||
{
|
||||
oldtime = temp;
|
||||
first = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check for turnover or backward time
|
||||
if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000))
|
||||
{
|
||||
oldtime = temp; // so we can't get stuck
|
||||
}
|
||||
else
|
||||
{
|
||||
t2 = temp - oldtime;
|
||||
|
||||
time = (double)t2 * pfreq;
|
||||
oldtime = temp;
|
||||
|
||||
curtime += time;
|
||||
|
||||
if (curtime == lastcurtime)
|
||||
{
|
||||
sametimecount++;
|
||||
|
||||
if (sametimecount > 100000)
|
||||
{
|
||||
curtime += 1.0;
|
||||
sametimecount = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sametimecount = 0;
|
||||
}
|
||||
|
||||
lastcurtime = curtime;
|
||||
}
|
||||
}
|
||||
|
||||
Sys_PopFPCW ();
|
||||
|
||||
return curtime;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_InitFloatTime
|
||||
================
|
||||
*/
|
||||
void Sys_InitFloatTime (void)
|
||||
{
|
||||
int j;
|
||||
|
||||
Sys_DoubleTime ();
|
||||
|
||||
j = COM_CheckParm("-starttime");
|
||||
|
||||
if (j)
|
||||
{
|
||||
curtime = (double) (Q_atof(com_argv[j+1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
curtime = 0.0;
|
||||
}
|
||||
|
||||
lastcurtime = curtime;
|
||||
}
|
||||
|
||||
#endif
|
||||
// DWORD starttime;
|
||||
double Sys_DoubleTime (void)
|
||||
{
|
||||
static DWORD starttime;
|
||||
static qboolean first = true;
|
||||
DWORD now;
|
||||
// double t;
|
||||
|
||||
now = timeGetTime();
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
starttime = now;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (now < starttime) // wrapped?
|
||||
{
|
||||
double r;
|
||||
r = (now / 1000.0) + (LONG_MAX - starttime / 1000.0);
|
||||
starttime = now;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (now - starttime == 0)
|
||||
return 0.0;
|
||||
|
||||
return (now - starttime) / 1000.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
//the system console stuff
|
||||
|
||||
char *Sys_ConsoleInput (void)
|
||||
{
|
||||
static char text[256];
|
||||
static int len;
|
||||
INPUT_RECORD recs[1024];
|
||||
// int count;
|
||||
int i;
|
||||
int ch;
|
||||
DWORD numevents, numread, dummy=0;
|
||||
HANDLE th;
|
||||
char *clipText, *textCopied;
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
|
||||
Sys_Error ("Error getting # of console events");
|
||||
|
||||
if (numevents <= 0)
|
||||
break;
|
||||
|
||||
if (!ReadConsoleInput(hinput, recs, 1, &numread))
|
||||
Sys_Error ("Error reading console input");
|
||||
|
||||
if (numread != 1)
|
||||
Sys_Error ("Couldn't read console input");
|
||||
|
||||
if (recs[0].EventType == KEY_EVENT)
|
||||
{
|
||||
if (recs[0].Event.KeyEvent.bKeyDown)
|
||||
{
|
||||
ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '\r':
|
||||
WriteFile(houtput, "\r\n", 2, &dummy, NULL);
|
||||
|
||||
if (len)
|
||||
{
|
||||
text[len] = 0;
|
||||
len = 0;
|
||||
return text;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
if (len)
|
||||
{
|
||||
len--;
|
||||
WriteFile(houtput, "\b \b", 3, &dummy, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (((ch=='V' || ch=='v') && (recs[0].Event.KeyEvent.dwControlKeyState &
|
||||
(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) || ((recs[0].Event.KeyEvent.dwControlKeyState
|
||||
& SHIFT_PRESSED) && (recs[0].Event.KeyEvent.wVirtualKeyCode
|
||||
==VK_INSERT))) {
|
||||
if (OpenClipboard(NULL)) {
|
||||
th = GetClipboardData(CF_TEXT);
|
||||
if (th) {
|
||||
clipText = GlobalLock(th);
|
||||
if (clipText) {
|
||||
textCopied = BZ_Malloc(GlobalSize(th)+1);
|
||||
strcpy(textCopied, clipText);
|
||||
/* Substitutes a NULL for every token */strtok(textCopied, "\n\r\b");
|
||||
i = strlen(textCopied);
|
||||
if (i+len>=256)
|
||||
i=256-len;
|
||||
if (i>0) {
|
||||
textCopied[i]=0;
|
||||
text[len]=0;
|
||||
strcat(text, textCopied);
|
||||
len+=dummy;
|
||||
WriteFile(houtput, textCopied, i, &dummy, NULL);
|
||||
}
|
||||
BZ_Free(textCopied);
|
||||
}
|
||||
GlobalUnlock(th);
|
||||
}
|
||||
CloseClipboard();
|
||||
}
|
||||
} else if (ch >= ' ')
|
||||
{
|
||||
WriteFile(houtput, &ch, 1, &dummy, NULL);
|
||||
text[len] = ch;
|
||||
len = (len + 1) & 0xff;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL WINAPI HandlerRoutine (DWORD dwCtrlType)
|
||||
{
|
||||
switch (dwCtrlType)
|
||||
{
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
case CTRL_CLOSE_EVENT:
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
Cbuf_AddText ("quit\n", RESTRICT_LOCAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean Sys_InitTerminal (void)
|
||||
{
|
||||
if (!AllocConsole())
|
||||
return false;
|
||||
SetConsoleCtrlHandler (HandlerRoutine, TRUE);
|
||||
SetConsoleTitle ("FTE dedicated server");
|
||||
hinput = GetStdHandle (STD_INPUT_HANDLE);
|
||||
houtput = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
|
||||
return true;
|
||||
}
|
||||
void Sys_CloseTerminal (void)
|
||||
{
|
||||
FreeConsole();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
////////////////////////////
|
||||
|
||||
void Sys_Sleep (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Sys_SendKeyEvents (void)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
if (!qrenderer)
|
||||
{
|
||||
SV_GetConsoleCommands ();
|
||||
return;
|
||||
}
|
||||
|
||||
while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
|
||||
{
|
||||
// we always update if there are any event, even if we're paused
|
||||
scr_skipupdate = 0;
|
||||
|
||||
if (!GetMessage (&msg, NULL, 0, 0))
|
||||
break;
|
||||
// Sys_Quit ();
|
||||
TranslateMessage (&msg);
|
||||
DispatchMessage (&msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sys_ServerActivity(void)
|
||||
{
|
||||
FlashWindow(mainwindow, true);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
WINDOWS CRAP
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
WinMain
|
||||
==================
|
||||
*/
|
||||
void SleepUntilInput (int time)
|
||||
{
|
||||
|
||||
MsgWaitForMultipleObjects(1, &tevent, FALSE, time, QS_ALLINPUT);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
WinMain
|
||||
==================
|
||||
*/
|
||||
HINSTANCE global_hInstance;
|
||||
int global_nCmdShow;
|
||||
char *argv[MAX_NUM_ARGVS];
|
||||
static char exename[256];
|
||||
HWND hwnd_dialog;
|
||||
|
||||
#ifndef CLIENTONLY
|
||||
qboolean isDedicated = false;
|
||||
#endif
|
||||
|
||||
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
// MSG msg;
|
||||
quakeparms_t parms;
|
||||
double time, oldtime, newtime;
|
||||
MEMORYSTATUS lpBuffer;
|
||||
static char cwd[1024];
|
||||
int t;
|
||||
RECT rect;
|
||||
|
||||
/* previous instances do not exist in Win32 */
|
||||
if (hPrevInstance)
|
||||
return 0;
|
||||
|
||||
global_hInstance = hInstance;
|
||||
global_nCmdShow = nCmdShow;
|
||||
|
||||
lpBuffer.dwLength = sizeof(MEMORYSTATUS);
|
||||
GlobalMemoryStatus (&lpBuffer);
|
||||
|
||||
GetModuleFileName(NULL, cwd, sizeof(cwd)-1);
|
||||
strcpy(exename, COM_SkipPath(cwd));
|
||||
|
||||
parms.argc = 1;
|
||||
argv[0] = exename;
|
||||
|
||||
while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS))
|
||||
{
|
||||
while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
|
||||
lpCmdLine++;
|
||||
|
||||
if (*lpCmdLine)
|
||||
{
|
||||
argv[parms.argc] = lpCmdLine;
|
||||
parms.argc++;
|
||||
|
||||
while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
|
||||
lpCmdLine++;
|
||||
|
||||
if (*lpCmdLine)
|
||||
{
|
||||
*lpCmdLine = 0;
|
||||
lpCmdLine++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
parms.argv = argv;
|
||||
|
||||
COM_InitArgv (parms.argc, parms.argv);
|
||||
|
||||
TL_InitLanguages();
|
||||
//tprints are now allowed
|
||||
|
||||
if (!GetCurrentDirectory (sizeof(cwd), cwd))
|
||||
Sys_Error ("Couldn't determine current directory");
|
||||
|
||||
if (cwd[Q_strlen(cwd)-1] == '/' || cwd[Q_strlen(cwd)-1] == '\\')
|
||||
cwd[Q_strlen(cwd)-1] = 0;
|
||||
|
||||
parms.basedir = cwd;
|
||||
parms.cachedir = NULL;
|
||||
|
||||
parms.argc = com_argc;
|
||||
parms.argv = com_argv;
|
||||
|
||||
#ifndef CLIENTONLY
|
||||
if (COM_CheckParm ("-dedicated"))
|
||||
{
|
||||
isDedicated = true;
|
||||
hwnd_dialog=NULL;
|
||||
|
||||
if (!Sys_InitTerminal())
|
||||
Sys_Error ("Couldn't allocate dedicated server console");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL);
|
||||
|
||||
if (hwnd_dialog)
|
||||
{
|
||||
if (GetWindowRect (hwnd_dialog, &rect))
|
||||
{
|
||||
if (rect.left > (rect.top * 2))
|
||||
{
|
||||
SetWindowPos (hwnd_dialog, 0,
|
||||
(rect.left / 2) - ((rect.right - rect.left) / 2),
|
||||
rect.top, 0, 0,
|
||||
SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
ShowWindow (hwnd_dialog, SW_SHOWDEFAULT);
|
||||
UpdateWindow (hwnd_dialog);
|
||||
SetForegroundWindow (hwnd_dialog);
|
||||
}
|
||||
|
||||
// take the greater of all the available memory or half the total memory,
|
||||
// but at least 8 Mb and no more than 16 Mb, unless they explicitly
|
||||
// request otherwise
|
||||
parms.memsize = lpBuffer.dwAvailPhys;
|
||||
|
||||
if (parms.memsize < MINIMUM_WIN_MEMORY)
|
||||
parms.memsize = MINIMUM_WIN_MEMORY;
|
||||
|
||||
if (parms.memsize < (lpBuffer.dwTotalPhys >> 1))
|
||||
parms.memsize = lpBuffer.dwTotalPhys >> 1;
|
||||
|
||||
// if (parms.memsize > MAXIMUM_WIN_MEMORY)
|
||||
// parms.memsize = MAXIMUM_WIN_MEMORY;
|
||||
|
||||
if (COM_CheckParm ("-heapsize"))
|
||||
{
|
||||
t = COM_CheckParm("-heapsize") + 1;
|
||||
|
||||
if (t < com_argc)
|
||||
parms.memsize = Q_atoi (com_argv[t]) * 1024;
|
||||
}
|
||||
else if (COM_CheckParm ("-mem"))
|
||||
{
|
||||
t = COM_CheckParm("-mem") + 1;
|
||||
|
||||
if (t < com_argc)
|
||||
parms.memsize = Q_atoi (com_argv[t]) * 1024;
|
||||
}
|
||||
|
||||
parms.membase = VirtualAlloc (NULL, parms.memsize, MEM_RESERVE, PAGE_NOACCESS);
|
||||
// parms.membase = malloc (parms.memsize);
|
||||
|
||||
if (!parms.membase)
|
||||
Sys_Error ("Not enough memory free; check disk space\n");
|
||||
|
||||
#ifndef CLIENTONLY
|
||||
if (isDedicated) //compleate denial to switch to anything else - many of the client structures are not initialized.
|
||||
{
|
||||
SV_Init (&parms);
|
||||
|
||||
SV_Frame (0.1);
|
||||
|
||||
oldtime = Sys_DoubleTime () - 0.1;
|
||||
while (1)
|
||||
{
|
||||
if (!isDedicated)
|
||||
Sys_Error("Dedicated was cleared");
|
||||
NET_Sleep(100, false);
|
||||
|
||||
// find time passed since last cycle
|
||||
newtime = Sys_DoubleTime ();
|
||||
time = newtime - oldtime;
|
||||
oldtime = newtime;
|
||||
|
||||
SV_Frame (time);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
tevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
if (!tevent)
|
||||
Sys_Error ("Couldn't create event");
|
||||
|
||||
Sys_Init ();
|
||||
|
||||
// because sound is off until we become active
|
||||
S_BlockSound ();
|
||||
|
||||
Sys_Printf ("Host_Init\n");
|
||||
Host_Init (&parms);
|
||||
|
||||
oldtime = Sys_DoubleTime ();
|
||||
|
||||
|
||||
//client console should now be initialized.
|
||||
|
||||
/* main window message loop */
|
||||
while (1)
|
||||
{
|
||||
if (isDedicated)
|
||||
{
|
||||
NET_Sleep(100, false);
|
||||
|
||||
// find time passed since last cycle
|
||||
newtime = Sys_DoubleTime ();
|
||||
time = newtime - oldtime;
|
||||
oldtime = newtime;
|
||||
|
||||
SV_Frame (time);
|
||||
}
|
||||
else
|
||||
{
|
||||
// yield the CPU for a little while when paused, minimized, or not the focus
|
||||
if (((cl.paused && (!ActiveApp && !DDActive)) || Minimized || block_drawing) && !media_filmtype)
|
||||
{
|
||||
SleepUntilInput (PAUSE_SLEEP);
|
||||
scr_skipupdate = 1; // no point in bothering to draw
|
||||
}
|
||||
else if (!ActiveApp && !DDActive && !media_filmtype)
|
||||
{
|
||||
SleepUntilInput (NOT_FOCUS_SLEEP);
|
||||
}
|
||||
|
||||
newtime = Sys_DoubleTime ();
|
||||
time = newtime - oldtime;
|
||||
Host_Frame (time);
|
||||
oldtime = newtime;
|
||||
|
||||
Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* return success of application */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef NOASM //these couldn't be found... (it is a masm thing, right?)
|
||||
void Sys_HighFPPrecision (void)
|
||||
{
|
||||
}
|
||||
|
||||
void Sys_LowFPPrecision (void)
|
||||
{
|
||||
}
|
||||
|
||||
void Sys_SetFPCW (void)
|
||||
{
|
||||
}
|
||||
|
||||
void MaskExceptions (void)
|
||||
{
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// sys_wina.s
|
||||
// x86 assembly-language Win-dependent routines.
|
||||
|
||||
#include "asm_i386.h"
|
||||
#include "quakeasm.h"
|
||||
|
||||
#ifndef NOASM
|
||||
|
||||
//@@@ should be id386-dependent, and have an equivalent C path
|
||||
|
||||
.data
|
||||
|
||||
.align 4
|
||||
fpenv:
|
||||
.long 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
.text
|
||||
|
||||
.globl C(MaskExceptions)
|
||||
C(MaskExceptions):
|
||||
fnstenv fpenv
|
||||
orl $0x3F,fpenv
|
||||
fldenv fpenv
|
||||
|
||||
ret
|
||||
|
||||
#if 0
|
||||
.globl C(unmaskexceptions)
|
||||
C(unmaskexceptions):
|
||||
fnstenv fpenv
|
||||
andl $0xFFFFFFE0,fpenv
|
||||
fldenv fpenv
|
||||
|
||||
ret
|
||||
#endif
|
||||
|
||||
.data
|
||||
|
||||
.align 4
|
||||
.globl ceil_cw, single_cw, full_cw, cw, pushed_cw
|
||||
ceil_cw: .long 0
|
||||
single_cw: .long 0
|
||||
full_cw: .long 0
|
||||
cw: .long 0
|
||||
pushed_cw: .long 0
|
||||
|
||||
.text
|
||||
|
||||
.globl C(Sys_LowFPPrecision)
|
||||
C(Sys_LowFPPrecision):
|
||||
fldcw single_cw
|
||||
|
||||
ret
|
||||
|
||||
.globl C(Sys_HighFPPrecision)
|
||||
C(Sys_HighFPPrecision):
|
||||
fldcw full_cw
|
||||
|
||||
ret
|
||||
|
||||
.globl C(Sys_PushFPCW_SetHigh)
|
||||
C(Sys_PushFPCW_SetHigh):
|
||||
fnstcw pushed_cw
|
||||
fldcw full_cw
|
||||
|
||||
ret
|
||||
|
||||
.globl C(Sys_PopFPCW)
|
||||
C(Sys_PopFPCW):
|
||||
fldcw pushed_cw
|
||||
|
||||
ret
|
||||
|
||||
.globl C(Sys_SetFPCW)
|
||||
C(Sys_SetFPCW):
|
||||
fnstcw cw
|
||||
movl cw,%eax
|
||||
#if id386
|
||||
andb $0xF0,%ah
|
||||
orb $0x03,%ah // round mode, 64-bit precision
|
||||
#endif
|
||||
movl %eax,full_cw
|
||||
|
||||
#if id386
|
||||
andb $0xF0,%ah
|
||||
orb $0x0C,%ah // chop mode, single precision
|
||||
#endif
|
||||
movl %eax,single_cw
|
||||
|
||||
#if id386
|
||||
andb $0xF0,%ah
|
||||
orb $0x08,%ah // ceil mode, single precision
|
||||
#endif
|
||||
movl %eax,ceil_cw
|
||||
|
||||
ret
|
||||
|
||||
#endif
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
|
||||
Teamplay.c
|
||||
Contains various console stuff for improving the performance of a team...
|
||||
Cheats I hear you say?...
|
||||
|
||||
Personally, I'd rather call it a hack job.
|
||||
Most of it is dependant upon specific mod types - TF.
|
||||
|
||||
|
||||
As far as split screen goes, this is all relative to player 0. We don't provide more than one say command.
|
||||
*/
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
#ifndef ZQUAKETEAMPLAY
|
||||
|
||||
cvar_t tp_name_armortype_ga = {"tp_name_armortype_ga", "g"};
|
||||
cvar_t tp_name_armortype_ya = {"tp_name_armortype_ya", "y"};
|
||||
cvar_t tp_name_armortype_ra = {"tp_name_armortype_ra", "r"};
|
||||
cvar_t tp_name_none = {"tp_name_none", ""};
|
||||
|
||||
|
||||
#define translatetext(i) #i
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//Macros.
|
||||
|
||||
char *TP_ClassForTFSkin(void)
|
||||
{
|
||||
char *skin;
|
||||
skin = Info_ValueForKey(cls.userinfo, "skin");
|
||||
if (!*skin)
|
||||
return "Classless";
|
||||
if (skin[0] != 't' && skin[1] != 'f' && skin[2] != '_')
|
||||
return skin;
|
||||
if (!strcmp(skin, "tf_sold"))
|
||||
return translatetext(TLTP_CLASS_SOLIDER);
|
||||
if (!strcmp(skin, "tf_demo"))
|
||||
return translatetext(TLTP_CLASS_DEMOGUY);
|
||||
if (!strcmp(skin, "tf_eng"))
|
||||
return translatetext(TLTP_CLASS_ENGINEER);
|
||||
if (!strcmp(skin, "tf_snipe"))
|
||||
return translatetext(TLTP_CLASS_SNIPER);
|
||||
if (!strcmp(skin, "tf_hwguy"))
|
||||
return translatetext(TLTP_CLASS_HWGUY);
|
||||
if (!strcmp(skin, "tf_medic"))
|
||||
return translatetext(TLTP_CLASS_MEDIC);
|
||||
if (!strcmp(skin, "tf_pyro"))
|
||||
return translatetext(TLTP_CLASS_PYRO);
|
||||
if (!strcmp(skin, "tf_scout"))
|
||||
return translatetext(TLTP_CLASS_SCOUT);
|
||||
if (!strcmp(skin, "tf_spy"))
|
||||
return translatetext(TLTP_CLASS_SPY);
|
||||
|
||||
return skin;
|
||||
}
|
||||
|
||||
void *TP_ArmourType(void)
|
||||
{
|
||||
if (cl.stats[0][STAT_ITEMS] & IT_ARMOR1)
|
||||
return tp_name_armortype_ga.string;
|
||||
else if (cl.stats[0][STAT_ITEMS] & IT_ARMOR2)
|
||||
return tp_name_armortype_ya.string;
|
||||
else if (cl.stats[0][STAT_ITEMS] & IT_ARMOR3)
|
||||
return tp_name_armortype_ra.string;
|
||||
else
|
||||
return tp_name_none.string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//Locs
|
||||
|
||||
typedef struct location_s {
|
||||
vec3_t pos;
|
||||
struct location_s *next;
|
||||
char name[0];
|
||||
} location_t;
|
||||
location_t *location;
|
||||
|
||||
char LocationLevel[64];
|
||||
|
||||
void CL_LoadLocs(void)
|
||||
{
|
||||
location_t *newloc;
|
||||
vec3_t pos;
|
||||
|
||||
char *file;
|
||||
char *end;
|
||||
char name[MAX_QPATH];
|
||||
// if (!strcmp(LocationLevel, cl.model_name[1]))
|
||||
// return;
|
||||
|
||||
while(location)
|
||||
{
|
||||
newloc = location->next;
|
||||
Z_Free(location);
|
||||
location = newloc;
|
||||
}
|
||||
|
||||
strcpy(LocationLevel, cl.model_name[1]);
|
||||
|
||||
COM_StripExtension(COM_SkipPath(LocationLevel), name);
|
||||
file = COM_LoadTempFile(va("locs/%s.loc", name));
|
||||
|
||||
if (!file)
|
||||
return;
|
||||
for(;;)
|
||||
{
|
||||
file = COM_Parse(file);
|
||||
pos[0] = atof(com_token)/8;
|
||||
file = COM_Parse(file);
|
||||
pos[1] = atof(com_token)/8;
|
||||
file = COM_Parse(file);
|
||||
pos[2] = atof(com_token)/8;
|
||||
|
||||
while(*file && *file <= '\0')
|
||||
file++;
|
||||
|
||||
if (!file)
|
||||
return;
|
||||
end = strchr(file, '\n');
|
||||
if (!end)
|
||||
{
|
||||
end = file + strlen(file);
|
||||
}
|
||||
newloc = Z_Malloc(sizeof(location_t) + end-file+1);
|
||||
newloc->next = location;
|
||||
location = newloc;
|
||||
|
||||
Q_strncpyz(newloc->name, file, end-file);
|
||||
VectorCopy(pos, newloc->pos);
|
||||
|
||||
|
||||
if (!*end)
|
||||
return;
|
||||
file = end+1;
|
||||
}
|
||||
}
|
||||
|
||||
char *CL_LocationName(float *pos)
|
||||
{
|
||||
location_t *loc;
|
||||
vec3_t dir;
|
||||
char *best;
|
||||
float dist, bestdist;
|
||||
|
||||
CL_LoadLocs();
|
||||
|
||||
if (!location)
|
||||
return "somewhere";
|
||||
|
||||
//get the initial one
|
||||
best = location->name;
|
||||
VectorSubtract(location->pos, pos, dir);
|
||||
bestdist = VectorNormalize(dir);
|
||||
|
||||
//check for a closer one.
|
||||
for (loc = location->next; loc; loc=loc->next)
|
||||
{
|
||||
VectorSubtract(loc->pos, pos, dir);
|
||||
dist = VectorNormalize(dir);
|
||||
if (dist < bestdist)
|
||||
{
|
||||
best = loc->name;
|
||||
bestdist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
//Commands
|
||||
#define INVIS_CHAR1 12
|
||||
#define INVIS_CHAR2 138
|
||||
#define INVIS_CHAR3 160
|
||||
|
||||
#ifdef ZQUAKETEAMPLAY
|
||||
/*
|
||||
===============
|
||||
CL_Say
|
||||
|
||||
Handles both say and say_team
|
||||
===============
|
||||
*/
|
||||
void CL_Say (qboolean team)
|
||||
{
|
||||
extern cvar_t cl_fakename;
|
||||
char text[1024], sendtext[1024], *s;
|
||||
|
||||
if (Cmd_Argc() < 2)
|
||||
{
|
||||
if (team)
|
||||
Con_Printf ("%s <text>: send a team message\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.state == ca_disconnected)
|
||||
{
|
||||
Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
SZ_Print (&cls.netchan.message, team ? "say_team " : "say ");
|
||||
|
||||
s = TP_ParseMacroString (Cmd_Args());
|
||||
Q_strncpyz (text, TP_ParseFunChars (s, true), sizeof(text));
|
||||
|
||||
sendtext[0] = 0;
|
||||
if (team && !cl.spectator && cl_fakename.string[0] &&
|
||||
!strchr(s, '\x0d') /* explicit $\ in message overrides cl_fakename */)
|
||||
{
|
||||
char buf[1024];
|
||||
Cmd_ExpandString (cl_fakename.string, buf);
|
||||
strcpy (buf, TP_ParseMacroString (buf));
|
||||
Q_snprintfz (sendtext, sizeof(sendtext), "\x0d%s: ", TP_ParseFunChars(buf, true));
|
||||
}
|
||||
|
||||
strlcat (sendtext, text, sizeof(sendtext));
|
||||
|
||||
if (sendtext[0] < 32)
|
||||
SZ_Print (&cls.netchan.message, "\""); // add quotes so that old servers parse the message correctly
|
||||
|
||||
SZ_Print (&cls.netchan.message, sendtext);
|
||||
|
||||
if (sendtext[0] < 32)
|
||||
SZ_Print (&cls.netchan.message, "\""); // add quotes so that old servers parse the message correctly
|
||||
}
|
||||
|
||||
|
||||
void CL_Say_f (void)
|
||||
{
|
||||
CL_Say (false);
|
||||
}
|
||||
|
||||
void CL_SayTeam_f (void)
|
||||
{
|
||||
CL_Say (true);
|
||||
}
|
||||
|
||||
#else
|
||||
void CL_Say_f (void)
|
||||
{
|
||||
char string[256];
|
||||
char *msg;
|
||||
int c;
|
||||
if (cls.state == ca_disconnected || cls.demoplayback)
|
||||
{
|
||||
#ifndef CLIENT_ONLY
|
||||
if (sv.state)
|
||||
SV_ConSay_f();
|
||||
else
|
||||
#endif
|
||||
Con_TPrintf (TL_CANTXNOTCONNECTED, Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp("sayone", Cmd_Argv(0)))
|
||||
{
|
||||
if (strcmp(Info_ValueForKey(cl.serverinfo, "*distrib"), DISTRIBUTION) || atoi(Info_ValueForKey(cl.serverinfo, "*ver")) < PRE_SAYONE)
|
||||
{
|
||||
Con_TPrintf (TLC_REQUIRESSERVERMOD, Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
Q_strncpyz(string, Cmd_Argv(0), sizeof(string));
|
||||
for (msg = string; *msg; msg++)
|
||||
if (*msg >= 'A' && *msg <= 'Z')
|
||||
*msg = *msg - 'A' + 'a';
|
||||
SZ_Print (&cls.netchan.message, string);
|
||||
cls.netchan.message.cursize--;
|
||||
|
||||
msg = Cmd_Args();
|
||||
|
||||
if (Cmd_Argc() > 1)
|
||||
{
|
||||
SZ_Print (&cls.netchan.message," ");
|
||||
cls.netchan.message.cursize--;
|
||||
MSG_WriteChar(&cls.netchan.message, '\"');
|
||||
while(*msg)
|
||||
{
|
||||
c = *msg;
|
||||
|
||||
if (c == '%')
|
||||
{
|
||||
char *message = NULL;
|
||||
msg++;
|
||||
|
||||
if (message == NULL)
|
||||
switch(*msg)
|
||||
{
|
||||
case 'n':
|
||||
SZ_Print(&cls.netchan.message, name.string);
|
||||
cls.netchan.message.cursize--;
|
||||
msg++;
|
||||
continue;
|
||||
case 'h':
|
||||
SZ_Print(&cls.netchan.message, va("%i", cl.stats[0][STAT_HEALTH]));
|
||||
cls.netchan.message.cursize--; //remove the null term
|
||||
msg++;
|
||||
continue;
|
||||
case 'a':
|
||||
SZ_Print(&cls.netchan.message, va("%i", cl.stats[0][STAT_ARMOR]));
|
||||
cls.netchan.message.cursize--;
|
||||
msg++;
|
||||
continue;
|
||||
case 'A':
|
||||
SZ_Print(&cls.netchan.message, TP_ArmourType());
|
||||
cls.netchan.message.cursize--;
|
||||
msg++;
|
||||
continue;
|
||||
case 'l':
|
||||
SZ_Print(&cls.netchan.message, CL_LocationName(r_refdef.vieworg));
|
||||
cls.netchan.message.cursize--;
|
||||
msg++;
|
||||
continue;
|
||||
case 'S':
|
||||
SZ_Print(&cls.netchan.message, TP_ClassForTFSkin());
|
||||
cls.netchan.message.cursize--;
|
||||
msg++;
|
||||
continue;
|
||||
case '\0': //whoops.
|
||||
MSG_WriteChar(&cls.netchan.message, '%');
|
||||
MSG_WriteChar(&cls.netchan.message, '\"');
|
||||
MSG_WriteChar(&cls.netchan.message, *msg);
|
||||
return;
|
||||
case '%':
|
||||
c = '%';
|
||||
break;
|
||||
default:
|
||||
c = '%';
|
||||
msg--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (c == '$')
|
||||
{
|
||||
msg++;
|
||||
switch(*msg)
|
||||
{
|
||||
case '\\': c = 0x0D; break;
|
||||
case ':': c = 0x0A; break;
|
||||
case '[': c = 0x10; break;
|
||||
case ']': c = 0x11; break;
|
||||
case 'G': c = 0x86; break;
|
||||
case 'R': c = 0x87; break;
|
||||
case 'Y': c = 0x88; break;
|
||||
case 'B': c = 0x89; break;
|
||||
case '(': c = 0x80; break;
|
||||
case '=': c = 0x81; break;
|
||||
case ')': c = 0x82; break;
|
||||
case 'a': c = 0x83; break;
|
||||
case '<': c = 0x1d; break;
|
||||
case '-': c = 0x1e; break;
|
||||
case '>': c = 0x1f; break;
|
||||
case ',': c = 0x1c; break;
|
||||
case '.': c = 0x9c; break;
|
||||
case 'b': c = 0x8b; break;
|
||||
case 'c':
|
||||
case 'd': c = 0x8d; break;
|
||||
case '$': c = '$'; break;
|
||||
case '^': c = '^'; break;
|
||||
case 'x':
|
||||
c = INVIS_CHAR1;
|
||||
break;
|
||||
case 'y':
|
||||
c = INVIS_CHAR2;
|
||||
break;
|
||||
case 'z':
|
||||
c = INVIS_CHAR3;
|
||||
break;
|
||||
default:
|
||||
msg--;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MSG_WriteChar(&cls.netchan.message, c);
|
||||
|
||||
msg++;
|
||||
}
|
||||
MSG_WriteChar(&cls.netchan.message, '\"');
|
||||
}
|
||||
|
||||
MSG_WriteChar(&cls.netchan.message, '\0');
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
qboolean TP_SoundTrigger(char *message) //if there is a trigger there, play it. Return true if we found one, stripping off the file (it's neater that way).
|
||||
{
|
||||
char *strip;
|
||||
char *lineend = NULL;
|
||||
char soundname[128];
|
||||
int filter = 0;
|
||||
|
||||
for (strip = message+strlen(message)-1; *strip && strip >= message; strip--)
|
||||
{
|
||||
if (*strip == '#')
|
||||
filter++;
|
||||
if (*strip == ':')
|
||||
break; //if someone says just one word, we can take any tidles in thier name to be a voice command
|
||||
if (*strip == '\n')
|
||||
lineend = strip;
|
||||
else if (*strip <= ' ')
|
||||
{
|
||||
if (filter == 0 || filter == 1) //allow one space in front of a filter.
|
||||
{
|
||||
filter++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (*strip == '~')
|
||||
{
|
||||
//looks like a trigger, whoopie!
|
||||
if (lineend-strip > sizeof(soundname)-1)
|
||||
{
|
||||
Con_Printf("Sound trigger's file-name was too long\n");
|
||||
return false;
|
||||
}
|
||||
Q_strncpyz(soundname, strip+1, lineend-strip);
|
||||
memmove(strip, lineend, strlen(lineend)+1);
|
||||
|
||||
Cbuf_AddText(va("play %s\n", soundname), RESTRICT_LOCAL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TP_Init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void TP_CheckPickupSound(char *s, vec3_t org)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,992 @@
|
|||
//DMW
|
||||
|
||||
/*
|
||||
F1 will return to progs.src
|
||||
F2 will try to open a file with the name of which is on that line. (excluding comments/tabs). Needs conditions.
|
||||
F3 will give a prompt for typing in a value name to see the value.
|
||||
F4 will save
|
||||
F5 will run (unbreak).
|
||||
F6 will list the stack.
|
||||
F7 will compile.
|
||||
F8 will move execution
|
||||
F9 will set a break point.
|
||||
F10 will apply code changes.
|
||||
F11 will step through.
|
||||
*/
|
||||
|
||||
#include "quakedef.h"
|
||||
#ifdef TEXTEDITOR
|
||||
cvar_t alloweditor = {"alloweditor", "1"}; //disallow loading editor for stepbystep debugging.
|
||||
cvar_t editstripcr = {"edit_stripcr", "1"}; //remove \r from eols (on load).
|
||||
cvar_t editaddcr = {"edit_addcr", "1"}; //make sure that each line ends with a \r (on save).
|
||||
cvar_t edittabspacing = {"edit_tabsize", "4"};
|
||||
|
||||
#undef pr_trace
|
||||
|
||||
progfuncs_t *editprogfuncs;
|
||||
|
||||
typedef struct fileblock_s {
|
||||
struct fileblock_s *next;
|
||||
struct fileblock_s *prev;
|
||||
int allocatedlength;
|
||||
int datalength;
|
||||
int flags;
|
||||
char *data;
|
||||
} fileblock_t;
|
||||
#define FB_BREAK 1
|
||||
|
||||
fileblock_t *cursorblock, *firstblock, *executionblock, *viewportystartblock;
|
||||
|
||||
void *E_Malloc(int size)
|
||||
{
|
||||
char *mem;
|
||||
mem = Z_Malloc(size);
|
||||
if (!mem)
|
||||
Sys_Error("Failed to allocate enough mem for editor\n");
|
||||
return mem;
|
||||
}
|
||||
void E_Free(void *mem)
|
||||
{
|
||||
Z_Free(mem);
|
||||
}
|
||||
|
||||
#define GETBLOCK(s, ret) ret = (void *)E_Malloc(sizeof(fileblock_t) + s);ret->allocatedlength = s;ret->data = (char *)ret + sizeof(fileblock_t)
|
||||
|
||||
|
||||
char OpenEditorFile[256];
|
||||
|
||||
|
||||
qboolean editoractive; //(export)
|
||||
qboolean editormodal; //doesn't return. (export)
|
||||
qboolean editorblocking;
|
||||
qboolean madechanges;
|
||||
qboolean insertkeyhit;
|
||||
qboolean useeval;
|
||||
|
||||
char evalstring[256];
|
||||
|
||||
int executionlinenum; //step by step debugger
|
||||
int cursorlinenum, cursorx;
|
||||
|
||||
int viewportx;
|
||||
int viewporty;
|
||||
|
||||
|
||||
//newsize = number of chars, EXCLUDING terminator.
|
||||
void MakeNewSize(fileblock_t *block, int newsize) //this is used to resize a block. It allocates a new one, copys the data frees the old one and links it into the right place
|
||||
//it is called when the user is typing
|
||||
{
|
||||
fileblock_t *newblock;
|
||||
|
||||
newsize = (newsize + 4)&~3; //We allocate a bit extra, so we don't need to keep finding a new block for each and every character.
|
||||
|
||||
if (block->allocatedlength >= newsize)
|
||||
return; //Ignore. This block is too large already. Don't bother resizeing, cos that's pretty much pointless.
|
||||
|
||||
GETBLOCK(newsize, newblock);
|
||||
memcpy(newblock->data, block->data, block->datalength);
|
||||
newblock->prev = block->prev;
|
||||
newblock->next = block->next;
|
||||
if (newblock->prev)
|
||||
newblock->prev->next = newblock;
|
||||
if (newblock->next)
|
||||
newblock->next->prev = newblock;
|
||||
|
||||
newblock->datalength = block->datalength;
|
||||
newblock->flags = block->flags;
|
||||
|
||||
E_Free(block);
|
||||
|
||||
if (firstblock == block)
|
||||
firstblock = newblock;
|
||||
|
||||
if (cursorblock == block)
|
||||
cursorblock = newblock;
|
||||
}
|
||||
|
||||
int positionacross;
|
||||
void GetCursorpos(void)
|
||||
{
|
||||
int a;
|
||||
char *s;
|
||||
int ts = edittabspacing.value;
|
||||
if (ts < 1)
|
||||
ts = 4;
|
||||
for (a=0,positionacross=0,s=cursorblock->data;a < cursorx && *s;s++,a++)
|
||||
{
|
||||
if (*s == '\t')
|
||||
{
|
||||
positionacross += ts;
|
||||
positionacross -= cursorx%ts;
|
||||
}
|
||||
else
|
||||
positionacross++;
|
||||
}
|
||||
// positionacross = cursorofs;
|
||||
}
|
||||
void SetCursorpos(void)
|
||||
{
|
||||
int a=0;
|
||||
char *s;
|
||||
int ts = edittabspacing.value;
|
||||
if (ts < 1)
|
||||
ts = 4;
|
||||
for (cursorx=0,s=cursorblock->data;cursorx < positionacross && *s;s++,a++)
|
||||
{
|
||||
if (*s == '\t')
|
||||
{
|
||||
cursorx += ts;
|
||||
cursorx -= cursorx%ts;
|
||||
}
|
||||
else
|
||||
cursorx++;
|
||||
}
|
||||
cursorx=a;
|
||||
|
||||
//just in case
|
||||
if (cursorx > cursorblock->datalength)
|
||||
cursorx = cursorblock->datalength;
|
||||
}
|
||||
|
||||
|
||||
void CloseEditor(void)
|
||||
{
|
||||
fileblock_t *b;
|
||||
|
||||
key_dest = key_console;
|
||||
editoractive = false;
|
||||
|
||||
if (!firstblock)
|
||||
return;
|
||||
OpenEditorFile[0] = '\0';
|
||||
|
||||
for (b = firstblock; b;)
|
||||
{
|
||||
firstblock = b;
|
||||
b=b->next;
|
||||
E_Free(firstblock);
|
||||
}
|
||||
|
||||
madechanges = false;
|
||||
|
||||
firstblock = NULL;
|
||||
|
||||
executionlinenum = -1;
|
||||
}
|
||||
|
||||
qboolean EditorSaveFile(char *s) //returns true if succesful
|
||||
{
|
||||
|
||||
// FILE *F;
|
||||
fileblock_t *b;
|
||||
|
||||
int len=0;
|
||||
int pos=0;
|
||||
char *data;
|
||||
|
||||
for (b = firstblock; b; b = b->next) //find total length required.
|
||||
{
|
||||
len += b->datalength;
|
||||
len+=2; //extra for \n
|
||||
}
|
||||
|
||||
data = Hunk_TempAlloc(len);
|
||||
|
||||
for (b = firstblock; b; b = b->next) //find total length required.
|
||||
{
|
||||
memcpy(data + pos, b->data, b->datalength);
|
||||
pos += b->datalength;
|
||||
if (editaddcr.value)
|
||||
{
|
||||
data[pos]='\r';
|
||||
pos++;
|
||||
}
|
||||
data[pos]='\n';
|
||||
pos++;
|
||||
}
|
||||
|
||||
COM_WriteFile(s, data, len);
|
||||
/*
|
||||
F = fopen(s, "wt");
|
||||
if (!F)
|
||||
return false;
|
||||
for (b = firstblock; b; b = b->next)
|
||||
{
|
||||
fprintf(F, "%s\n", b->data);
|
||||
}
|
||||
fclose(F);
|
||||
*/
|
||||
madechanges = false;
|
||||
executionlinenum = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EditorNewFile()
|
||||
{
|
||||
GETBLOCK(64, firstblock);
|
||||
GETBLOCK(64, firstblock->next);
|
||||
firstblock->next->prev = firstblock;
|
||||
cursorblock = firstblock;
|
||||
cursorlinenum = 0;
|
||||
cursorx = 0;
|
||||
|
||||
viewportystartblock = NULL;
|
||||
|
||||
madechanges = true;
|
||||
executionlinenum = -1;
|
||||
|
||||
key_dest = key_editor;
|
||||
editoractive = true;
|
||||
}
|
||||
|
||||
void EditorOpenFile(char *name)
|
||||
{
|
||||
int i;
|
||||
char line[8192];
|
||||
int len, flen, pos=0;
|
||||
FILE *F;
|
||||
fileblock_t *b;
|
||||
|
||||
CloseEditor();
|
||||
|
||||
strcpy(OpenEditorFile, name);
|
||||
|
||||
if ((flen=COM_FOpenFile(OpenEditorFile, &F)) == -1)
|
||||
{
|
||||
sprintf(OpenEditorFile, "src/%s", name);
|
||||
if ((flen=COM_FOpenFile(OpenEditorFile, &F)) == -1)
|
||||
{
|
||||
F = fopen(OpenEditorFile, "rb");
|
||||
if (F)
|
||||
flen = COM_filelength(F);
|
||||
else
|
||||
{
|
||||
Con_Printf("Couldn't open file \"%s\"\nA new file will be created\n", name);
|
||||
strcpy(OpenEditorFile, name);
|
||||
key_dest = key_console;
|
||||
EditorNewFile();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
i=1;
|
||||
|
||||
while(pos < flen)
|
||||
{
|
||||
len = 0;
|
||||
for(;;)
|
||||
{
|
||||
if (pos+len >= flen)
|
||||
break;
|
||||
line[len] = fgetc(F);
|
||||
|
||||
if (line[len] == '\n')
|
||||
break;
|
||||
len++;
|
||||
}
|
||||
pos+=len;
|
||||
pos++; //and a \n
|
||||
|
||||
if (editstripcr.value)
|
||||
{
|
||||
if (line[len-1] == '\r')
|
||||
len--;
|
||||
}
|
||||
|
||||
b = firstblock;
|
||||
|
||||
GETBLOCK(len+1, firstblock);
|
||||
firstblock->prev = b;
|
||||
if (b)
|
||||
b->next = firstblock;
|
||||
|
||||
firstblock->datalength = len;
|
||||
|
||||
memcpy(firstblock->data, line, len);
|
||||
if (svprogfuncs)
|
||||
if (svprogfuncs->ToggleBreak(svprogfuncs, OpenEditorFile+strlen(com_gamedir)+1, i, 3))
|
||||
{
|
||||
firstblock->flags |= FB_BREAK;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
if (firstblock == NULL)
|
||||
{
|
||||
GETBLOCK(10, firstblock);
|
||||
}
|
||||
else
|
||||
for (; firstblock->prev; firstblock=firstblock->prev);
|
||||
fclose(F);
|
||||
|
||||
cursorblock = firstblock;
|
||||
cursorx = 0;
|
||||
|
||||
viewportystartblock = NULL;
|
||||
|
||||
madechanges = false;
|
||||
executionlinenum = -1;
|
||||
|
||||
key_dest = key_editor;
|
||||
editoractive = true;
|
||||
}
|
||||
|
||||
void Editor_Key(int key)
|
||||
{
|
||||
int i;
|
||||
if (keybindings[key][0])
|
||||
if (!strcmp(keybindings[key][0], "toggleconsole"))
|
||||
{
|
||||
key_dest = key_console;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if (CmdAfterSave)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case 'Y':
|
||||
case 'y':
|
||||
if (!EditorSaveFile(OpenEditorFile))
|
||||
{
|
||||
Con_Printf("Couldn't save file \"%s\"\n", OpenEditorFile);
|
||||
key_dest = key_console;
|
||||
}
|
||||
else if (!CmdAfterSaveCalled)
|
||||
{
|
||||
CmdAfterSaveCalled=true;
|
||||
(*CmdAfterSave)();
|
||||
CmdAfterSaveCalled=false;
|
||||
}
|
||||
CmdAfterSave = NULL;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
case 'n':
|
||||
(*CmdAfterSave)();
|
||||
CmdAfterSave = NULL;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
case 'c':
|
||||
CmdAfterSave = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
*/
|
||||
if (key == K_SHIFT)
|
||||
return;
|
||||
|
||||
if (useeval && key != K_F11)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case K_ESCAPE:
|
||||
useeval = false;
|
||||
break;
|
||||
case K_DEL:
|
||||
evalstring[0] = '\0';
|
||||
break;
|
||||
case K_BACKSPACE:
|
||||
i = strlen(evalstring);
|
||||
if (i < 1)
|
||||
break;
|
||||
evalstring[i-1] = '\0';
|
||||
break;
|
||||
default:
|
||||
i = strlen(evalstring);
|
||||
evalstring[i] = key;
|
||||
evalstring[i+1] = '\0';
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* if (ctrl_down && (key == 'c' || key == K_INS))
|
||||
key = K_F9;
|
||||
if ((ctrl_down && key == 'v') || (shift_down && key == K_INS))
|
||||
key = K_F10;
|
||||
*/
|
||||
switch (key)
|
||||
{
|
||||
case K_SHIFT:
|
||||
break;
|
||||
case K_ALT:
|
||||
break;
|
||||
case K_CTRL:
|
||||
break;
|
||||
case K_PGUP:
|
||||
GetCursorpos();
|
||||
{int a=(vid.height/8)/2;
|
||||
while(a) {a--;
|
||||
if (cursorblock->prev)
|
||||
{
|
||||
cursorblock = cursorblock->prev;
|
||||
cursorlinenum--;
|
||||
}
|
||||
}
|
||||
}
|
||||
SetCursorpos();
|
||||
break;
|
||||
case K_PGDN:
|
||||
GetCursorpos();
|
||||
{int a=(vid.height/8)/2;
|
||||
while(a)
|
||||
{
|
||||
a--;
|
||||
if (cursorblock->next)
|
||||
{
|
||||
cursorblock = cursorblock->next;
|
||||
cursorlinenum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
SetCursorpos();
|
||||
break;
|
||||
|
||||
// case K_BACK:
|
||||
case K_F1:
|
||||
// Editor_f();
|
||||
break;
|
||||
// case K_FORWARD:
|
||||
case K_F2:
|
||||
{
|
||||
char file[1024];
|
||||
char *s;
|
||||
Q_strncpyz(file, cursorblock->data, sizeof(file));
|
||||
s = file;
|
||||
while (*s)
|
||||
{
|
||||
if ((*s == '/' && s[1] == '/') || (*s == '\t'))
|
||||
{
|
||||
*s = '\0';
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (*file)
|
||||
EditorOpenFile(file);
|
||||
}
|
||||
break;
|
||||
case K_F3:
|
||||
useeval = true;
|
||||
break;
|
||||
case K_F4:
|
||||
EditorSaveFile(OpenEditorFile);
|
||||
break;
|
||||
case K_F5:
|
||||
editormodal = false;
|
||||
if (editprogfuncs)
|
||||
*editprogfuncs->pr_trace = false;
|
||||
break;
|
||||
case K_F6:
|
||||
if (editprogfuncs)
|
||||
editprogfuncs->PR_StackTrace(editprogfuncs);
|
||||
break;
|
||||
case K_F7:
|
||||
EditorSaveFile(OpenEditorFile);
|
||||
Cbuf_AddText("compile\n", RESTRICT_LOCAL);
|
||||
break;
|
||||
case K_F8:
|
||||
executionlinenum = cursorlinenum;
|
||||
executionblock = cursorblock;
|
||||
break;
|
||||
case K_F9:
|
||||
{
|
||||
int f = 0;
|
||||
#ifndef CLIENTONLY
|
||||
if (svprogfuncs)
|
||||
{
|
||||
if (svprogfuncs->ToggleBreak(svprogfuncs, OpenEditorFile+strlen(com_gamedir)+1, cursorlinenum, 2))
|
||||
f |= 1;
|
||||
else
|
||||
f |= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (f & 1)
|
||||
cursorblock->flags |= FB_BREAK;
|
||||
else
|
||||
cursorblock->flags &= ~FB_BREAK;
|
||||
}
|
||||
break;
|
||||
case K_F10:
|
||||
EditorSaveFile(OpenEditorFile);
|
||||
Cbuf_AddText("applycompile\n", RESTRICT_LOCAL);
|
||||
break;
|
||||
case K_F11:
|
||||
editormodal = false;
|
||||
break;
|
||||
// case K_STOP:
|
||||
case K_ESCAPE:
|
||||
CloseEditor();
|
||||
break;
|
||||
|
||||
case K_HOME:
|
||||
cursorx = 0;
|
||||
break;
|
||||
case K_END:
|
||||
cursorx = cursorblock->datalength;
|
||||
break;
|
||||
|
||||
case K_LEFTARROW:
|
||||
cursorx--;
|
||||
if (cursorx < 0)
|
||||
cursorx = 0;
|
||||
break;
|
||||
|
||||
case K_RIGHTARROW:
|
||||
cursorx++;
|
||||
if (cursorx > cursorblock->datalength)
|
||||
cursorx = cursorblock->datalength;
|
||||
break;
|
||||
|
||||
case K_MWHEELUP:
|
||||
case K_UPARROW:
|
||||
|
||||
GetCursorpos();
|
||||
if (cursorblock->prev)
|
||||
{
|
||||
cursorblock = cursorblock->prev;
|
||||
cursorlinenum--;
|
||||
}
|
||||
SetCursorpos();
|
||||
break;
|
||||
case K_MWHEELDOWN:
|
||||
case K_DOWNARROW:
|
||||
|
||||
GetCursorpos();
|
||||
if (cursorblock->next)
|
||||
{
|
||||
cursorblock = cursorblock->next;
|
||||
cursorlinenum++;
|
||||
}
|
||||
|
||||
SetCursorpos();
|
||||
break;
|
||||
|
||||
case K_BACKSPACE:
|
||||
cursorx--;
|
||||
if (cursorx < 0)
|
||||
{
|
||||
fileblock_t *b = cursorblock;
|
||||
|
||||
if (b == firstblock) //no line above to remove to
|
||||
{
|
||||
cursorx=0;
|
||||
break;
|
||||
}
|
||||
|
||||
cursorlinenum-=1;
|
||||
madechanges = true;
|
||||
|
||||
cursorblock = b->prev;
|
||||
|
||||
MakeNewSize(cursorblock, b->datalength + cursorblock->datalength+5);
|
||||
|
||||
cursorx = cursorblock->datalength;
|
||||
memcpy(cursorblock->data + cursorblock->datalength, b->data, b->datalength);
|
||||
|
||||
cursorblock->next = b->next;
|
||||
if (b->next)
|
||||
b->next->prev = cursorblock;
|
||||
// cursorblock->prev->next = cursorblock->next;
|
||||
// cursorblock->next->prev = cursorblock->prev;
|
||||
|
||||
E_Free(b);
|
||||
// cursorblock = b;
|
||||
|
||||
break;
|
||||
}
|
||||
case K_DEL: //bksp falls through.
|
||||
{
|
||||
int a;
|
||||
fileblock_t *b;
|
||||
|
||||
cursorlinenum=-1;
|
||||
madechanges = true;
|
||||
//FIXME: does this work right?
|
||||
if (!cursorblock->datalength && cursorblock->next && cursorblock->prev) //blank line
|
||||
{
|
||||
b = cursorblock;
|
||||
if (b->next)
|
||||
b->next->prev = b->prev;
|
||||
if (b->prev)
|
||||
b->prev->next = b->next;
|
||||
|
||||
if (cursorblock->next)
|
||||
cursorblock = cursorblock->next;
|
||||
else
|
||||
cursorblock = cursorblock->prev;
|
||||
|
||||
E_Free(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (a = cursorx; a < cursorblock->datalength;a++)
|
||||
cursorblock->data[a] = cursorblock->data[a+1];
|
||||
cursorblock->datalength--;
|
||||
}
|
||||
|
||||
if (cursorx >= cursorblock->datalength)
|
||||
cursorx = cursorblock->datalength-1;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_ENTER:
|
||||
{
|
||||
fileblock_t *b = cursorblock;
|
||||
|
||||
cursorlinenum=-1;
|
||||
|
||||
madechanges = true;
|
||||
|
||||
GETBLOCK(strlen(b->data+cursorx), cursorblock);
|
||||
cursorblock->next = b->next;
|
||||
cursorblock->prev = b;
|
||||
b->next = cursorblock;
|
||||
if (cursorblock->next)
|
||||
cursorblock->next->prev = cursorblock;
|
||||
if (cursorblock->prev)
|
||||
cursorblock->prev->next = cursorblock;
|
||||
|
||||
strcpy(cursorblock->data, b->data+cursorx);
|
||||
b->data[cursorx] = '\0';
|
||||
|
||||
cursorx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_INS:
|
||||
insertkeyhit = insertkeyhit?false:true;
|
||||
break;
|
||||
default:
|
||||
if ((key < ' ' || key > 127) && key != '\t') //we deem these as unprintable
|
||||
break;
|
||||
|
||||
if (insertkeyhit) //insert a char
|
||||
{
|
||||
char *s;
|
||||
|
||||
madechanges = true;
|
||||
|
||||
MakeNewSize(cursorblock, cursorblock->datalength+5); //allocate a bit extra, so we don't need to keep resizing it and shifting loads a data about
|
||||
|
||||
s = cursorblock->data + cursorblock->datalength;
|
||||
while (s >= cursorblock->data + cursorx)
|
||||
{
|
||||
s[1] = s[0];
|
||||
s--;
|
||||
}
|
||||
cursorx++;
|
||||
cursorblock->datalength++;
|
||||
*(s+1) = key;
|
||||
}
|
||||
else //over write a char
|
||||
{
|
||||
MakeNewSize(cursorblock, cursorblock->datalength+5); //not really needed
|
||||
|
||||
cursorblock->data[cursorx] = key;
|
||||
cursorx++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Draw_CursorLine(int ox, int y, fileblock_t *b)
|
||||
{
|
||||
int x=0;
|
||||
qbyte *d = b->data;
|
||||
int cx;
|
||||
int a = 0, i;
|
||||
|
||||
int colour=0;
|
||||
|
||||
int ts = edittabspacing.value;
|
||||
if (ts < 1)
|
||||
ts = 4;
|
||||
ts*=8;
|
||||
|
||||
if (b->flags & (FB_BREAK))
|
||||
colour = 1; //red
|
||||
|
||||
if (executionblock == b)
|
||||
{
|
||||
if (colour) //break point too
|
||||
colour = 2; //green
|
||||
else
|
||||
colour = 3; //yellow
|
||||
}
|
||||
|
||||
if (cursorx <= strlen(d)+1 && (int)(realtime*4.0) & 1)
|
||||
cx = -1;
|
||||
else
|
||||
cx = cursorx;
|
||||
for (i = 0; i < b->datalength; i++)
|
||||
{
|
||||
if (*d == '\t')
|
||||
{
|
||||
if (a == cx)
|
||||
Draw_ColouredCharacter (x+ox, y, 11);
|
||||
x+=ts;
|
||||
x-=x%ts;
|
||||
d++;
|
||||
a++;
|
||||
continue;
|
||||
}
|
||||
if (x+ox< vid.width)
|
||||
{
|
||||
if (a == cx)
|
||||
Draw_ColouredCharacter (x+ox, y, 11);
|
||||
else
|
||||
Draw_ColouredCharacter (x+ox, y, (int)*d | (colour<<8));
|
||||
}
|
||||
d++;
|
||||
x += 8;
|
||||
a++;
|
||||
}
|
||||
if (a == cx)
|
||||
Draw_ColouredCharacter (x+ox, y, 11);
|
||||
}
|
||||
|
||||
void Draw_NonCursorLine(int x, int y, fileblock_t *b)
|
||||
{
|
||||
int nx = 0;
|
||||
qbyte *d = b->data;
|
||||
int i;
|
||||
|
||||
int colour=0;
|
||||
|
||||
int ts = edittabspacing.value;
|
||||
if (ts < 1)
|
||||
ts = 4;
|
||||
ts*=8;
|
||||
|
||||
if (b->flags & (FB_BREAK))
|
||||
colour = 1; //red
|
||||
|
||||
if (executionblock == b)
|
||||
{
|
||||
if (colour) //break point too
|
||||
colour = 2; //green
|
||||
else
|
||||
colour = 3; //yellow
|
||||
}
|
||||
|
||||
for (i = 0; i < b->datalength; i++)
|
||||
{
|
||||
if (*d == '\t')
|
||||
{
|
||||
nx+=ts;
|
||||
nx-=nx%ts;
|
||||
d++;
|
||||
continue;
|
||||
}
|
||||
if (x+nx < vid.width)
|
||||
Draw_ColouredCharacter (x+nx, y, (int)*d | (colour<<8));
|
||||
d++;
|
||||
nx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
fileblock_t *firstline(void)
|
||||
{
|
||||
int lines;
|
||||
fileblock_t *b;
|
||||
lines = (vid.height/8)/2-1;
|
||||
b = cursorblock;
|
||||
if (!b)
|
||||
return NULL;
|
||||
while (1)
|
||||
{
|
||||
if (!b->prev)
|
||||
return b;
|
||||
b = b->prev;
|
||||
lines--;
|
||||
if (lines <= 0)
|
||||
return b;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Editor_Draw(void)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
fileblock_t *b;
|
||||
|
||||
if (key_dest != key_console)
|
||||
key_dest = key_editor;
|
||||
|
||||
if ((editoractive && cls.state == ca_disconnected) || editormodal)
|
||||
Draw_EditorBackground (vid.height);
|
||||
|
||||
if (cursorlinenum < 0) //look for the cursor line num
|
||||
{
|
||||
cursorlinenum = 0;
|
||||
for (b = firstblock; b; b=b->next)
|
||||
{
|
||||
cursorlinenum++;
|
||||
if (b == cursorblock)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!viewportystartblock) //look for the cursor line num
|
||||
{
|
||||
y = 0;
|
||||
for (viewportystartblock = firstblock; viewportystartblock; viewportystartblock=viewportystartblock->prev)
|
||||
{
|
||||
y++;
|
||||
if (y == viewporty)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
x=0;
|
||||
for (y = 0; y < cursorx; y++)
|
||||
{
|
||||
if (cursorblock->data[y] == '\0')
|
||||
break;
|
||||
else if (cursorblock->data[y] == '\t')
|
||||
{
|
||||
x+=32;
|
||||
x&=~31;
|
||||
}
|
||||
else
|
||||
x+=8;
|
||||
}
|
||||
x=-x + vid.width/2;
|
||||
if (x > 0)
|
||||
x = 0;
|
||||
|
||||
if (madechanges)
|
||||
Draw_Character (vid.width - 8, 0, '!'|128);
|
||||
if (!insertkeyhit)
|
||||
Draw_Character (vid.width - 16, 0, 'O'|128);
|
||||
Draw_String(0, 0, va("%6i:%4i:%s", cursorlinenum, cursorx+1, OpenEditorFile));
|
||||
|
||||
if (useeval)
|
||||
{
|
||||
if (!editprogfuncs)
|
||||
useeval = false;
|
||||
else
|
||||
{
|
||||
Draw_String(0, 8, evalstring);
|
||||
Draw_String(vid.width/2, 8, editprogfuncs->EvaluateDebugString(editprogfuncs, evalstring));
|
||||
}
|
||||
y = 16;
|
||||
}
|
||||
else
|
||||
y=8;
|
||||
b = firstline();
|
||||
for (; b; b=b->next)
|
||||
{
|
||||
if (b == cursorblock)
|
||||
Draw_CursorLine(x, y, b);
|
||||
else
|
||||
Draw_NonCursorLine(x, y, b);
|
||||
y+=8;
|
||||
|
||||
if (y > vid.height)
|
||||
break;
|
||||
}
|
||||
|
||||
/* if (CmdAfterSave)
|
||||
{
|
||||
if (madechanges)
|
||||
{
|
||||
M_DrawTextBox (0, 0, 36, 5);
|
||||
M_PrintWhite (16, 12, OpenEditorFile);
|
||||
M_PrintWhite (16, 28, "Do you want to save the open file?");
|
||||
M_PrintWhite (16, 36, "[Y]es/[N]o/[C]ancel");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CmdAfterSaveCalled)
|
||||
{
|
||||
CmdAfterSaveCalled = true;
|
||||
(*CmdAfterSave) ();
|
||||
CmdAfterSaveCalled = false;
|
||||
}
|
||||
CmdAfterSave = NULL;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
int QCLibEditor(char *filename, int line, int nump, char **parms)
|
||||
{
|
||||
if (editormodal || !developer.value)
|
||||
return line; //whoops
|
||||
|
||||
if (!strncmp(OpenEditorFile, "src/", 4))
|
||||
{
|
||||
if (!editoractive || strcmp(OpenEditorFile+4, filename))
|
||||
{
|
||||
if (editoractive)
|
||||
EditorSaveFile(OpenEditorFile);
|
||||
|
||||
EditorOpenFile(filename);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!editoractive || strcmp(OpenEditorFile, filename))
|
||||
{
|
||||
if (editoractive)
|
||||
EditorSaveFile(OpenEditorFile);
|
||||
|
||||
EditorOpenFile(filename);
|
||||
}
|
||||
}
|
||||
|
||||
for (cursorlinenum = 1, cursorblock = firstblock; cursorlinenum < line && cursorblock->next; cursorlinenum++)
|
||||
cursorblock=cursorblock->next;
|
||||
|
||||
executionblock = cursorblock;
|
||||
|
||||
if (!parms)
|
||||
{
|
||||
editormodal = true;
|
||||
|
||||
while(editormodal && editoractive)
|
||||
{
|
||||
key_dest = key_editor;
|
||||
scr_disabled_for_loading=false;
|
||||
SCR_UpdateScreen();
|
||||
Sys_SendKeyEvents();
|
||||
|
||||
NET_Sleep(100, false); //any os.
|
||||
}
|
||||
|
||||
editormodal = false;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
void Editor_f(void)
|
||||
{
|
||||
if (editoractive)
|
||||
EditorSaveFile(OpenEditorFile);
|
||||
EditorOpenFile(Cmd_Argv(1));
|
||||
// EditorNewFile();
|
||||
}
|
||||
|
||||
void Editor_Init(void)
|
||||
{
|
||||
Cmd_AddCommand("edit", Editor_f);
|
||||
|
||||
Cvar_Register(&alloweditor, "Text editor");
|
||||
Cvar_Register(&editstripcr, "Text editor");
|
||||
Cvar_Register(&editaddcr, "Text editor");
|
||||
Cvar_Register(&edittabspacing, "Text editor");
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,654 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
#include "glquake.h" //overkill
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define ENV_READ_NAME "FTE_SECURE_CHANNEL_READ"
|
||||
#define ENV_WRITE_NAME "FTE_SECURE_CHANNEL_WRITE"
|
||||
|
||||
#define SECURE_CMD_CHECKMODEL 'c' // q: name:string, model:buffer
|
||||
// a: 'y' or 'n'
|
||||
|
||||
#define SECURE_CMD_GETVERSION 'g' // q: check_line:string, serverinfo:string, userinfo:string
|
||||
// a: ok, client_desc:string, crc:ulong
|
||||
|
||||
#define SECURE_CMD_CHECKVERSION 'v' // q: check_line:string, serverinfo:string, userinfo:string
|
||||
// a: ok, crc:ulong
|
||||
#define SECURE_CMD_CHECKVERSION2 'r' //SECURE_CMD_CHECKVERSION with the engine description appended on the end.
|
||||
//let's my front end work on a variety of engines rathar than just 1
|
||||
|
||||
#define SECURE_ANSWER_OK 'y'
|
||||
#define SECURE_ANSWER_YES 'y'
|
||||
#define SECURE_ANSWER_NO 'n'
|
||||
#define SECURE_ANSWER_ERROR 'n'
|
||||
|
||||
cvar_t allow_f_version = {"allow_f_version", "1"};
|
||||
cvar_t allow_f_server = {"allow_f_server", "1"};
|
||||
cvar_t allow_f_modified = {"allow_f_modified", "1"};
|
||||
cvar_t allow_f_skins = {"allow_f_skins", "1"};
|
||||
cvar_t auth_validateclients = {"auth_validateclients", "1"};
|
||||
|
||||
//
|
||||
// last f_queries
|
||||
//
|
||||
typedef struct f_query_s
|
||||
{
|
||||
char *query;
|
||||
char *serverinfo;
|
||||
char *c_userinfo[MAX_CLIENTS];
|
||||
qboolean c_exist[MAX_CLIENTS];
|
||||
|
||||
unsigned short crc;
|
||||
double timestamp;
|
||||
}
|
||||
f_query_t;
|
||||
|
||||
#define F_QUERIES_REMEMBERED 5
|
||||
f_query_t f_last_queries[F_QUERIES_REMEMBERED];
|
||||
int f_last_query_pos = 0;
|
||||
|
||||
typedef struct f_modified_s {
|
||||
char name[MAX_QPATH];
|
||||
qboolean ismodified;
|
||||
struct f_modified_s *next;
|
||||
} f_modified_t;
|
||||
|
||||
f_modified_t *f_modified_list;
|
||||
qboolean care_f_modified;
|
||||
qboolean f_modified_particles;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winquake.h"
|
||||
|
||||
typedef HANDLE qpipe;
|
||||
|
||||
// write to pipe, returns number of bytes written, or 0 = error
|
||||
int Sys_WritePipe(qpipe q_pipe, unsigned char *buf, int buflen)
|
||||
{
|
||||
DWORD dwBytesWritten;
|
||||
BOOL ret;
|
||||
|
||||
ret = WriteFile(
|
||||
q_pipe,
|
||||
(LPVOID) buf,
|
||||
buflen,
|
||||
&dwBytesWritten,
|
||||
NULL);
|
||||
|
||||
if (ret)
|
||||
return dwBytesWritten;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read from pipe, returns number of bytes read, or 0 = error
|
||||
int Sys_ReadPipe(qpipe q_pipe, unsigned char *buf, int buflen)
|
||||
{
|
||||
DWORD dwBytesRead;
|
||||
BOOL ret;
|
||||
|
||||
ret = ReadFile(
|
||||
q_pipe,
|
||||
(LPVOID) buf,
|
||||
buflen,
|
||||
&dwBytesRead,
|
||||
NULL);
|
||||
|
||||
if (ret)
|
||||
return dwBytesRead;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
typedef int qpipe;
|
||||
|
||||
int Sys_WritePipe(qpipe q_pipe, unsigned char *buf, int buflen)
|
||||
{
|
||||
return write(q_pipe, buf, buflen);
|
||||
}
|
||||
|
||||
int Sys_ReadPipe(qpipe q_pipe, unsigned char *buf, int buflen)
|
||||
{
|
||||
return read(q_pipe, buf, buflen);
|
||||
}
|
||||
#endif
|
||||
|
||||
static qpipe f_read, f_write;
|
||||
|
||||
int SPipe_ReadMemory(qpipe read_pipe, unsigned char *buf, int buflen)
|
||||
{
|
||||
int completed = 0;
|
||||
|
||||
while (completed < buflen)
|
||||
{
|
||||
int read;
|
||||
|
||||
read = Sys_ReadPipe(read_pipe, buf+completed, buflen-completed);
|
||||
|
||||
if (read == 0)
|
||||
return false;
|
||||
|
||||
completed += read;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int SPipe_ReadChar(qpipe read_pipe, char *c)
|
||||
{
|
||||
return SPipe_ReadMemory(read_pipe, (unsigned char *)c, 1);
|
||||
}
|
||||
|
||||
int SPipe_ReadInt(qpipe read_pipe, int *val)
|
||||
{
|
||||
return SPipe_ReadMemory(read_pipe, (unsigned char *)val, sizeof(int));
|
||||
}
|
||||
|
||||
int SPipe_ReadUlong(qpipe read_pipe, unsigned long *val)
|
||||
{
|
||||
return SPipe_ReadMemory(read_pipe, (unsigned char *)val, sizeof(unsigned long));
|
||||
}
|
||||
|
||||
int SPipe_ReadString(qpipe read_pipe, char *buf, int buflen)
|
||||
{
|
||||
int i;
|
||||
int slen;
|
||||
if (!SPipe_ReadInt(read_pipe, &slen))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < buflen && i < slen; i++)
|
||||
{
|
||||
if (!SPipe_ReadChar(read_pipe, buf+i))
|
||||
return false;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
for (; i < slen; i++) //now read the extra data that wouldn't fit.
|
||||
{
|
||||
if (!SPipe_ReadChar(read_pipe, buf+i))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int SPipe_WriteMemory(qpipe write_pipe, unsigned char *buf, int buflen)
|
||||
{
|
||||
int completed = 0;
|
||||
|
||||
while (completed < buflen)
|
||||
{
|
||||
int written;
|
||||
|
||||
written = Sys_WritePipe(write_pipe, buf+completed, buflen-completed);
|
||||
|
||||
if (written == 0)
|
||||
return written;
|
||||
|
||||
completed += written;
|
||||
}
|
||||
return completed;
|
||||
}
|
||||
|
||||
int SPipe_WriteChar(qpipe write_pipe, char c)
|
||||
{
|
||||
int written;
|
||||
written = SPipe_WriteMemory(write_pipe, (unsigned char *)(&c), 1);
|
||||
|
||||
return (written==1);
|
||||
}
|
||||
|
||||
int SPipe_WriteInt(qpipe write_pipe, int val)
|
||||
{
|
||||
int written;
|
||||
written = SPipe_WriteMemory(write_pipe, (unsigned char *)(&val), sizeof(int));
|
||||
|
||||
return (written==sizeof(int));
|
||||
}
|
||||
|
||||
int SPipe_WriteString(qpipe write_pipe, char *string)
|
||||
{
|
||||
int i;
|
||||
int len = strlen(string);
|
||||
if (!SPipe_WriteInt(write_pipe, len))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (!SPipe_WriteMemory(write_pipe, (unsigned char *)(string+i), 1))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CRC_AddBlock (unsigned short *crcvalue, qbyte *start, int count)
|
||||
{
|
||||
while (count--)
|
||||
CRC_ProcessByte(crcvalue, *start++);
|
||||
}
|
||||
|
||||
unsigned short SCRC_GetQueryStateCrc(char *f_query_string)
|
||||
{
|
||||
unsigned short crc;
|
||||
int i;
|
||||
char *tmp;
|
||||
|
||||
CRC_Init(&crc);
|
||||
|
||||
// add query
|
||||
CRC_AddBlock(&crc, f_query_string, strlen(f_query_string));
|
||||
|
||||
// add snapshot of serverinfo
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "deathmatch");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "teamplay");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "hostname");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "*progs");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "map");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "spawn");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "watervis");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "fraglimit");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "*gamedir");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.serverinfo, "timelimit");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
|
||||
// add snapshot of userinfo for every connected client
|
||||
for (i=0; i < MAX_CLIENTS; i++)
|
||||
if (cl.players[i].name[0])
|
||||
{
|
||||
tmp = Info_ValueForKey(cl.players[i].userinfo, "name");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
tmp = Info_ValueForKey(cl.players[i].userinfo, "team");
|
||||
CRC_AddBlock(&crc, tmp, strlen(tmp));
|
||||
}
|
||||
|
||||
// done
|
||||
return crc;
|
||||
}
|
||||
|
||||
void InitValidation(void)
|
||||
{
|
||||
char *read, *write;
|
||||
read = getenv(ENV_READ_NAME);
|
||||
write = getenv(ENV_WRITE_NAME);
|
||||
|
||||
Cvar_Register(&allow_f_version, "Authentication");
|
||||
Cvar_Register(&allow_f_modified, "Authentication");
|
||||
Cvar_Register(&allow_f_skins, "Authentication");
|
||||
Cvar_Register(&auth_validateclients, "Authentication");
|
||||
|
||||
if (!read || !write)
|
||||
return;
|
||||
|
||||
f_read = (qpipe)atoi(read);
|
||||
f_write = (qpipe)atoi(write);
|
||||
|
||||
if (!f_read || !f_write)
|
||||
{
|
||||
f_write = f_read = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ValidationThink (void)
|
||||
{
|
||||
}
|
||||
|
||||
void ValidationSendRequest (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Validation_FilesModified (void)
|
||||
{
|
||||
f_modified_t *fm;
|
||||
int count=0;
|
||||
char buf[1024];
|
||||
buf[0] = 0;
|
||||
|
||||
if (!allow_f_modified.value)
|
||||
return;
|
||||
|
||||
care_f_modified = true;
|
||||
|
||||
if (f_modified_particles)
|
||||
{
|
||||
strcat(buf, "modified: particles");
|
||||
count++;
|
||||
}
|
||||
|
||||
for (fm = f_modified_list; fm; fm = fm->next)
|
||||
{
|
||||
if (fm->ismodified)
|
||||
{
|
||||
char *tmp;
|
||||
if (!count)
|
||||
strcat(buf, "modified:");
|
||||
if (strlen(buf) < 250)
|
||||
{
|
||||
tmp = fm->name+1;
|
||||
while (strchr(tmp, '/'))
|
||||
tmp = strchr(tmp, '/')+1;
|
||||
strcat(buf, " ");
|
||||
strcat(buf, tmp);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(buf, " & more...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count == 0)
|
||||
strcat(buf, "all models ok");
|
||||
|
||||
Cbuf_AddText("say ", RESTRICT_LOCAL);
|
||||
Cbuf_AddText(buf, RESTRICT_LOCAL);
|
||||
Cbuf_AddText("\n", RESTRICT_LOCAL);
|
||||
}
|
||||
|
||||
void Validation_IncludeFile(char *filename, char *file, int filelen)
|
||||
{
|
||||
char result;
|
||||
f_modified_t *fm;
|
||||
|
||||
for (fm = f_modified_list; fm; fm = fm->next)
|
||||
{
|
||||
if (!strcmp(fm->name, filename))
|
||||
break;
|
||||
}
|
||||
if (!fm)
|
||||
{
|
||||
fm = Z_Malloc(sizeof(f_modified_t));
|
||||
fm->next = f_modified_list;
|
||||
f_modified_list = fm;
|
||||
Q_strncpyz(fm->name, filename, sizeof(fm->name));
|
||||
}
|
||||
|
||||
fm->ismodified = true;
|
||||
if (f_read && allow_f_modified.value)
|
||||
{
|
||||
SPipe_WriteChar(f_write, SECURE_CMD_CHECKMODEL);
|
||||
SPipe_WriteString(f_write, fm->name);
|
||||
SPipe_WriteInt (f_write, filelen);
|
||||
SPipe_WriteMemory(f_write, file, filelen);
|
||||
|
||||
SPipe_ReadChar(f_read, &result);
|
||||
|
||||
if (result == SECURE_ANSWER_YES)
|
||||
fm->ismodified = false;
|
||||
}
|
||||
if (fm->ismodified && care_f_modified)
|
||||
{
|
||||
Cbuf_AddText("say previous f_modified response is no longer valid.\n", RESTRICT_LOCAL);
|
||||
care_f_modified = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Validation_FlushFileList(void)
|
||||
{
|
||||
f_modified_t *fm;
|
||||
while(f_modified_list)
|
||||
{
|
||||
fm = f_modified_list->next;
|
||||
|
||||
Z_Free(f_modified_list);
|
||||
f_modified_list = fm;
|
||||
}
|
||||
}
|
||||
|
||||
void ValidationPrintVersion(char *f_query_string)
|
||||
{
|
||||
f_query_t *this_query;
|
||||
unsigned short query_crc;
|
||||
unsigned long crc;
|
||||
char answer;
|
||||
char name[128];
|
||||
char sr[256];
|
||||
int i;
|
||||
|
||||
switch(qrenderer)
|
||||
{
|
||||
#ifdef RGLQUAKE
|
||||
case QR_OPENGL:
|
||||
*sr = *"";
|
||||
break;
|
||||
#endif
|
||||
#ifdef SWQUAKE
|
||||
case QR_SOFTWARE:
|
||||
strcpy(sr, (r_pixbytes==4?"32bpp":"8bpp"));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*sr = *"";
|
||||
break;
|
||||
}
|
||||
if (f_read && allow_f_version.value)
|
||||
{
|
||||
query_crc = SCRC_GetQueryStateCrc(f_query_string);
|
||||
|
||||
//
|
||||
// remember this f_version
|
||||
//
|
||||
this_query = &f_last_queries[f_last_query_pos++ % F_QUERIES_REMEMBERED];
|
||||
this_query->timestamp = realtime;
|
||||
this_query->crc = query_crc;
|
||||
if (this_query->query)
|
||||
BZ_Free(this_query->query);
|
||||
this_query->query = BZ_Malloc(strlen(f_query_string)+1);
|
||||
strcpy(this_query->query, f_query_string);
|
||||
if (this_query->serverinfo)
|
||||
BZ_Free(this_query->serverinfo);
|
||||
this_query->serverinfo = BZ_Malloc(strlen(cl.serverinfo)+1);
|
||||
strcpy(this_query->serverinfo, cl.serverinfo);
|
||||
for (i=0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if (this_query->c_userinfo[i])
|
||||
{
|
||||
BZ_Free(this_query->c_userinfo[i]);
|
||||
this_query->c_userinfo[i] = NULL;
|
||||
}
|
||||
this_query->c_exist[i] = false;
|
||||
|
||||
if (cl.players[i].name[0])
|
||||
{
|
||||
this_query->c_exist[i] = true;
|
||||
this_query->c_userinfo[i] = BZ_Malloc(strlen(cl.players[i].userinfo)+1);
|
||||
strcpy(this_query->c_userinfo[i], cl.players[i].userinfo);
|
||||
}
|
||||
}
|
||||
|
||||
//now send the data.
|
||||
|
||||
SPipe_WriteChar(f_write, SECURE_CMD_GETVERSION);
|
||||
SPipe_WriteString(f_write, f_query_string);
|
||||
SPipe_WriteString(f_write, cl.serverinfo);
|
||||
SPipe_WriteString(f_write, cl.players[cl.playernum[0]].userinfo);
|
||||
|
||||
// get answer
|
||||
SPipe_ReadChar(f_read, &answer);
|
||||
SPipe_ReadString(f_read, name, 64);
|
||||
SPipe_ReadUlong(f_read, &crc);
|
||||
|
||||
if (answer == SECURE_ANSWER_OK)
|
||||
{
|
||||
// reply
|
||||
Cbuf_AddText("say ", RESTRICT_LOCAL);
|
||||
Cbuf_AddText(name, RESTRICT_LOCAL);
|
||||
if (*sr)
|
||||
Cbuf_AddText(va("/%s/%s", q_renderername, sr), RESTRICT_LOCAL);//extra info
|
||||
else
|
||||
Cbuf_AddText(va("/%s", q_renderername), RESTRICT_LOCAL);//extra info
|
||||
Cbuf_AddText(" ", RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("%04x", query_crc), RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("%08x", crc), RESTRICT_LOCAL);
|
||||
Cbuf_AddText("\n", RESTRICT_LOCAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (*sr)
|
||||
Cbuf_AddText (va("say "DISTRIBUTION"Quake v%4.3f-%i "PLATFORM"/%s/%s\n", VERSION, build_number(), q_renderername, sr), RESTRICT_RCON);
|
||||
else
|
||||
Cbuf_AddText (va("say "DISTRIBUTION"Quake v%4.3f-%i "PLATFORM"/%s\n", VERSION, build_number(), q_renderername), RESTRICT_RCON);
|
||||
}
|
||||
|
||||
void Validation_Skins(void)
|
||||
{
|
||||
extern cvar_t r_fullbrightSkins, r_fb_models;
|
||||
int percent = r_fullbrightSkins.value*100;
|
||||
if (percent < 0)
|
||||
percent = 0;
|
||||
if (percent > cls.allow_fbskins*100)
|
||||
percent = cls.allow_fbskins*100;
|
||||
if (percent)
|
||||
Cbuf_AddText(va("say all player skins %i%% fullbright%s\n", percent, r_fb_models.value?" (plus luma)":""), RESTRICT_LOCAL);
|
||||
else if (r_fb_models.value)
|
||||
Cbuf_AddText("say luma textures only\n", RESTRICT_LOCAL);
|
||||
else
|
||||
Cbuf_AddText("say Only cheaters use full bright skins\n", RESTRICT_LOCAL);
|
||||
}
|
||||
|
||||
void Validation_Server(void)
|
||||
{
|
||||
Cbuf_AddText(va("say server is %s\n", NET_AdrToString(cls.netchan.remote_address)), RESTRICT_LOCAL);
|
||||
}
|
||||
|
||||
void Validation_CheckIfResponse(char *text)
|
||||
{
|
||||
//client name, version type(os-renderer where it matters, os/renderer where renderer doesn't), 12 char hex crc
|
||||
int f_query_client;
|
||||
int i;
|
||||
char *crc;
|
||||
char *versionstring;
|
||||
|
||||
if (!f_read)
|
||||
return; //valid or not, we can't check it.
|
||||
|
||||
if (!auth_validateclients.value)
|
||||
return;
|
||||
|
||||
//do the parsing.
|
||||
{
|
||||
char *comp;
|
||||
int namelen;
|
||||
|
||||
for (crc = text + strlen(text) - 1; crc > text; crc--)
|
||||
if (*crc > ' ')
|
||||
break;
|
||||
|
||||
//find the crc.
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
if (crc <= text)
|
||||
return; //not enough chars.
|
||||
if ((*crc < '0' || *crc > '9') && (*crc < 'a' || *crc > 'f'))
|
||||
return; //not a hex char.
|
||||
crc--;
|
||||
}
|
||||
|
||||
//we now want 3 string seperated tokens, so the first starts at the fourth found ' ' + 1
|
||||
i = 4;
|
||||
for (comp = crc; ; comp--)
|
||||
{
|
||||
if (comp < text)
|
||||
return;
|
||||
if (*comp == ' ')
|
||||
{
|
||||
i--;
|
||||
if (!i)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
versionstring = comp+1;
|
||||
if (comp <= text)
|
||||
return; //not enough space for the 'name:'
|
||||
if (*(comp-1) != ':')
|
||||
return; //whoops. not a say.
|
||||
|
||||
namelen = comp - text-1;
|
||||
|
||||
for (f_query_client = 0; f_query_client < MAX_CLIENTS; f_query_client++)
|
||||
{
|
||||
if (strlen(cl.players[f_query_client].name) == namelen)
|
||||
if (!strncmp(cl.players[f_query_client].name, text, namelen))
|
||||
break;
|
||||
}
|
||||
if (f_query_client == MAX_CLIENTS)
|
||||
return; //looks like a validation, but it's not from a known client.
|
||||
|
||||
crc++;
|
||||
}
|
||||
|
||||
//now do the validation
|
||||
{
|
||||
f_query_t *query = NULL;
|
||||
int itemp;
|
||||
char buffer[10];
|
||||
unsigned short query_crc = 0;
|
||||
unsigned long user_crc = 0;
|
||||
unsigned long auth_crc = 0;
|
||||
char auth_answer;
|
||||
|
||||
//easy lame way to get the crc from hex.
|
||||
Q_strncpyS(buffer, crc, 4);
|
||||
buffer[4] = '\0';
|
||||
itemp = 0;
|
||||
sscanf(buffer, "%x", &itemp);
|
||||
query_crc = (unsigned long) itemp;
|
||||
|
||||
Q_strncpyS(buffer, crc+4, 8);
|
||||
buffer[8] = '\0';
|
||||
itemp = 0;
|
||||
sscanf(buffer, "%x", &itemp);
|
||||
user_crc = (unsigned long) itemp;
|
||||
|
||||
//
|
||||
// find that query
|
||||
//
|
||||
for (i=f_last_query_pos; i > f_last_query_pos-F_QUERIES_REMEMBERED; i--)
|
||||
{
|
||||
if (query_crc == f_last_queries[i % F_QUERIES_REMEMBERED].crc &&
|
||||
realtime - 5 < f_last_queries[i % F_QUERIES_REMEMBERED].timestamp)
|
||||
{
|
||||
query = &f_last_queries[i % F_QUERIES_REMEMBERED];
|
||||
}
|
||||
}
|
||||
|
||||
if (query == NULL)
|
||||
return; // reply to unknown query
|
||||
|
||||
if (!query->c_exist[f_query_client])
|
||||
return; // should never happen
|
||||
|
||||
// write request
|
||||
SPipe_WriteChar(f_write, SECURE_CMD_CHECKVERSION2);
|
||||
SPipe_WriteString(f_write, query->query);
|
||||
SPipe_WriteString(f_write, query->serverinfo);
|
||||
SPipe_WriteString(f_write, query->c_userinfo[f_query_client]);
|
||||
SPipe_WriteString(f_write, versionstring);
|
||||
|
||||
// get answer
|
||||
SPipe_ReadChar(f_read, &auth_answer);
|
||||
SPipe_ReadUlong(f_read, &auth_crc);
|
||||
|
||||
if (auth_answer == SECURE_ANSWER_YES && auth_crc == user_crc)
|
||||
{
|
||||
Con_Printf("Authentication Successful.\n");
|
||||
}
|
||||
else
|
||||
Con_Printf("^bAUTHENTICATION FAILED.\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// vid.h -- video driver defs
|
||||
|
||||
#define VID_CBITS 6
|
||||
#define VID_GRADES (1 << VID_CBITS)
|
||||
|
||||
// a pixel can be one, two, or four bytes
|
||||
typedef qbyte pixel_t;
|
||||
|
||||
typedef enum {QR_NONE, QR_SOFTWARE, QR_OPENGL} r_qrenderer_t;
|
||||
|
||||
typedef struct {
|
||||
//you are not allowed to make anything not work if it's not based on these vars...
|
||||
int width;
|
||||
int height;
|
||||
qboolean fullscreen;
|
||||
int bpp;
|
||||
int rate;
|
||||
float streach;
|
||||
char glrenderer[MAX_QPATH];
|
||||
r_qrenderer_t renderer;
|
||||
qboolean allow_modex;
|
||||
} rendererstate_t;
|
||||
|
||||
typedef struct vrect_s
|
||||
{
|
||||
int x,y,width,height;
|
||||
struct vrect_s *pnext;
|
||||
} vrect_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
pixel_t *buffer; // invisible buffer
|
||||
pixel_t *colormap; // 256 * VID_GRADES size
|
||||
unsigned short *colormap16; // 256 * VID_GRADES size
|
||||
int fullbright; // index of first fullbright color
|
||||
unsigned rowbytes; // may be > width if displayed in a window
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
float aspect; // width / height -- < 0 is taller than wide
|
||||
int numpages;
|
||||
int recalc_refdef; // if true, recalc vid-based stuff
|
||||
pixel_t *conbuffer;
|
||||
int conrowbytes;
|
||||
unsigned conwidth;
|
||||
unsigned conheight;
|
||||
int maxwarpwidth;
|
||||
int maxwarpheight;
|
||||
pixel_t *direct; // direct drawing to framebuffer, if not
|
||||
// NULL
|
||||
} viddef_t;
|
||||
|
||||
extern viddef_t vid; // global video state
|
||||
extern unsigned short d_8to16table[256];
|
||||
|
||||
extern unsigned int d_8to24bgrtable[256];
|
||||
extern unsigned int d_8to24rgbtable[256];
|
||||
extern unsigned int *d_8to32table;
|
||||
|
||||
#ifdef RGLQUAKE
|
||||
void GLVID_SetPalette (unsigned char *palette);
|
||||
// called at startup and after any gamma correction
|
||||
|
||||
void GLVID_ShiftPalette (unsigned char *palette);
|
||||
// called for bonus and pain flashes, and for underwater color changes
|
||||
|
||||
qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette);
|
||||
// Called at startup to set up translation tables, takes 256 8 bit RGB values
|
||||
// the palette data will go away after the call, so it must be copied off if
|
||||
// the video driver will need it again
|
||||
|
||||
void GLVID_Shutdown (void);
|
||||
// Called at shutdown
|
||||
|
||||
void GLVID_Update (vrect_t *rects);
|
||||
// flushes the given rectangles from the view buffer to the screen
|
||||
|
||||
int GLVID_SetMode (rendererstate_t *info, unsigned char *palette);
|
||||
// sets the mode; only used by the Quake engine for resetting to mode 0 (the
|
||||
// base mode) on memory allocation failures
|
||||
|
||||
void GLVID_HandlePause (qboolean pause);
|
||||
// called only on Win32, when pause happens, so the mouse can be released
|
||||
|
||||
void GLVID_LockBuffer (void);
|
||||
void GLVID_UnlockBuffer (void);
|
||||
|
||||
int GLVID_ForceUnlockedAndReturnState (void);
|
||||
void GLVID_ForceLockState (int lk);
|
||||
|
||||
qboolean GLVID_Is8bit();
|
||||
|
||||
void GLD_BeginDirectRect (int x, int y, qbyte *pbitmap, int width, int height);
|
||||
void GLD_EndDirectRect (int x, int y, int width, int height);
|
||||
char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight);
|
||||
#endif
|
||||
|
||||
#ifdef SWQUAKE
|
||||
void SWVID_SetPalette (unsigned char *palette);
|
||||
// called at startup and after any gamma correction
|
||||
|
||||
void SWVID_ShiftPalette (unsigned char *palette);
|
||||
// called for bonus and pain flashes, and for underwater color changes
|
||||
|
||||
qboolean SWVID_Init (rendererstate_t *info, unsigned char *palette);
|
||||
// Called at startup to set up translation tables, takes 256 8 bit RGB values
|
||||
// the palette data will go away after the call, so it must be copied off if
|
||||
// the video driver will need it again
|
||||
|
||||
void SWVID_Shutdown (void);
|
||||
// Called at shutdown
|
||||
|
||||
void SWVID_Update (vrect_t *rects);
|
||||
// flushes the given rectangles from the view buffer to the screen
|
||||
|
||||
void SWVID_HandlePause (qboolean pause);
|
||||
// called only on Win32, when pause happens, so the mouse can be released
|
||||
|
||||
void SWVID_LockBuffer (void);
|
||||
void SWVID_UnlockBuffer (void);
|
||||
|
||||
int SWVID_ForceUnlockedAndReturnState (void);
|
||||
void SWVID_ForceLockState (int lk);
|
||||
|
||||
char *SWVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// view.h
|
||||
|
||||
extern cvar_t v_gamma;
|
||||
extern cvar_t lcd_x;
|
||||
extern float v_blend[4];
|
||||
|
||||
extern int gl_ztrickdisabled;
|
||||
extern qboolean r_secondaryview;
|
||||
|
||||
void V_Init (void);
|
||||
void V_RenderView (void);
|
||||
float V_CalcRoll (vec3_t angles, vec3_t velocity);
|
||||
void GLV_UpdatePalette (void);
|
||||
void SWV_UpdatePalette (void);
|
||||
qboolean V_CheckGamma (void);
|
||||
void V_AddEntity(entity_t *in);
|
|
@ -0,0 +1,582 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// wad.c
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
int wad_numlumps;
|
||||
lumpinfo_t *wad_lumps;
|
||||
qbyte *wad_base;
|
||||
|
||||
void SwapPic (qpic_t *pic);
|
||||
|
||||
/*
|
||||
==================
|
||||
W_CleanupName
|
||||
|
||||
Lowercases name and pads with spaces and a terminating 0 to the length of
|
||||
lumpinfo_t->name.
|
||||
Used so lumpname lookups can proceed rapidly by comparing 4 chars at a time
|
||||
Space padding is so names can be printed nicely in tables.
|
||||
Can safely be performed in place.
|
||||
==================
|
||||
*/
|
||||
void W_CleanupName (char *in, char *out)
|
||||
{
|
||||
int i;
|
||||
int c;
|
||||
|
||||
for (i=0 ; i<16 ; i++ )
|
||||
{
|
||||
c = in[i];
|
||||
if (!c)
|
||||
break;
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c += ('a' - 'A');
|
||||
out[i] = c;
|
||||
}
|
||||
|
||||
for ( ; i< 16 ; i++ )
|
||||
out[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
W_LoadWadFile
|
||||
====================
|
||||
*/
|
||||
qbyte *COM_LoadFile (char *path, int usehunk);
|
||||
void W_LoadWadFile (char *filename)
|
||||
{
|
||||
lumpinfo_t *lump_p;
|
||||
wadinfo_t *header;
|
||||
unsigned i;
|
||||
int infotableofs;
|
||||
|
||||
if (wad_base)
|
||||
Z_Free(wad_base);
|
||||
|
||||
wad_base = COM_LoadFile (filename, 0);
|
||||
if (!wad_base)
|
||||
{
|
||||
wad_numlumps = 0;
|
||||
Con_Printf ("W_LoadWadFile: couldn't load %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
header = (wadinfo_t *)wad_base;
|
||||
|
||||
if (header->identification[0] != 'W'
|
||||
|| header->identification[1] != 'A'
|
||||
|| header->identification[2] != 'D'
|
||||
|| header->identification[3] != '2')
|
||||
Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename);
|
||||
|
||||
wad_numlumps = LittleLong(header->numlumps);
|
||||
infotableofs = LittleLong(header->infotableofs);
|
||||
wad_lumps = (lumpinfo_t *)(wad_base + infotableofs);
|
||||
|
||||
for (i=0, lump_p = wad_lumps ; i<wad_numlumps ; i++,lump_p++)
|
||||
{
|
||||
lump_p->filepos = LittleLong(lump_p->filepos);
|
||||
lump_p->size = LittleLong(lump_p->size);
|
||||
W_CleanupName (lump_p->name, lump_p->name);
|
||||
if (lump_p->type == TYP_QPIC)
|
||||
SwapPic ( (qpic_t *)(wad_base + lump_p->filepos));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
W_GetLumpinfo
|
||||
=============
|
||||
*/
|
||||
lumpinfo_t *W_GetLumpinfo (char *name)
|
||||
{
|
||||
int i;
|
||||
lumpinfo_t *lump_p;
|
||||
char clean[16];
|
||||
|
||||
W_CleanupName (name, clean);
|
||||
|
||||
for (lump_p=wad_lumps, i=0 ; i<wad_numlumps ; i++,lump_p++)
|
||||
{
|
||||
if (!strcmp(clean, lump_p->name))
|
||||
return lump_p;
|
||||
}
|
||||
|
||||
Sys_Error ("W_GetLumpinfo: %s not found", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *W_SafeGetLumpName (char *name)
|
||||
{
|
||||
int i;
|
||||
lumpinfo_t *lump_p;
|
||||
char clean[16];
|
||||
|
||||
W_CleanupName (name, clean);
|
||||
|
||||
for (lump_p=wad_lumps, i=0 ; i<wad_numlumps ; i++,lump_p++)
|
||||
{
|
||||
if (!strcmp(clean, lump_p->name))
|
||||
return (void *)(wad_base+lump_p->filepos);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *W_GetLumpName (char *name)
|
||||
{
|
||||
lumpinfo_t *lump;
|
||||
|
||||
lump = W_GetLumpinfo (name);
|
||||
|
||||
return (void *)(wad_base + lump->filepos);
|
||||
}
|
||||
|
||||
void *W_GetLumpNum (int num)
|
||||
{
|
||||
lumpinfo_t *lump;
|
||||
|
||||
if (num < 0 || num >= wad_numlumps)
|
||||
Sys_Error ("W_GetLumpNum: bad number: %i", num);
|
||||
|
||||
lump = wad_lumps + num;
|
||||
|
||||
return (void *)(wad_base + lump->filepos);
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
automatic qbyte swapping
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
void SwapPic (qpic_t *pic)
|
||||
{
|
||||
pic->width = LittleLong(pic->width);
|
||||
pic->height = LittleLong(pic->height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// based on origional code by LordHavoc
|
||||
|
||||
//FIXME: convert to linked list. is hunk possible?
|
||||
//hash tables?
|
||||
#define TEXWAD_MAXIMAGES 16384
|
||||
typedef struct
|
||||
{
|
||||
char name[16];
|
||||
FILE *file;
|
||||
int position;
|
||||
int size;
|
||||
} texwadlump_t;
|
||||
int numwadtextures;
|
||||
static texwadlump_t texwadlump[TEXWAD_MAXIMAGES];
|
||||
|
||||
typedef struct wadfile_s {
|
||||
char name[64];
|
||||
FILE *file;
|
||||
struct wadfile_s *next;
|
||||
} wadfile_t;
|
||||
|
||||
wadfile_t *openwadfiles;
|
||||
|
||||
void Wads_Flush (void)
|
||||
{
|
||||
wadfile_t *wf;
|
||||
while(openwadfiles)
|
||||
{
|
||||
fclose(openwadfiles->file);
|
||||
|
||||
wf = openwadfiles->next;
|
||||
Z_Free(openwadfiles);
|
||||
openwadfiles = wf;
|
||||
}
|
||||
|
||||
numwadtextures=0;
|
||||
}
|
||||
/*
|
||||
====================
|
||||
W_LoadTextureWadFile
|
||||
====================
|
||||
*/
|
||||
void W_LoadTextureWadFile (char *filename, int complain)
|
||||
{
|
||||
lumpinfo_t *lumps, *lump_p;
|
||||
wadinfo_t header;
|
||||
int i, j;
|
||||
int infotableofs;
|
||||
FILE *file;
|
||||
int numlumps;
|
||||
|
||||
wadfile_t *wf = openwadfiles;
|
||||
while(wf)
|
||||
{
|
||||
if (!strcmp(wf->name, filename)) //already loaded
|
||||
return;
|
||||
|
||||
wf = wf->next;
|
||||
}
|
||||
|
||||
COM_FOpenFile (filename, &file);
|
||||
if (!file)
|
||||
COM_FOpenFile (va("textures/halflife/%s", filename), &file);
|
||||
if (!file)
|
||||
{
|
||||
if (complain)
|
||||
Con_Printf ("W_LoadTextureWadFile: couldn't find %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fread(&header, 1, sizeof(wadinfo_t), file) != sizeof(wadinfo_t))
|
||||
{Con_Printf ("W_LoadTextureWadFile: unable to read wad header");return;}
|
||||
|
||||
if(memcmp(header.identification, "WAD3", 4))
|
||||
{Con_Printf ("W_LoadTextureWadFile: Wad file %s doesn't have WAD3 id\n",filename);return;}
|
||||
|
||||
numlumps = LittleLong(header.numlumps);
|
||||
if (numlumps < 1 || numlumps > TEXWAD_MAXIMAGES)
|
||||
{Con_Printf ("W_LoadTextureWadFile: invalid number of lumps (%i)\n", numlumps);return;}
|
||||
infotableofs = LittleLong(header.infotableofs);
|
||||
if (fseek(file, infotableofs, SEEK_SET))
|
||||
{Con_Printf ("W_LoadTextureWadFile: unable to seek to lump table");return;}
|
||||
if (!((lumps = Hunk_TempAlloc(sizeof(lumpinfo_t)*numlumps))))
|
||||
{Con_Printf ("W_LoadTextureWadFile: unable to allocate temporary memory for lump table");return;}
|
||||
|
||||
if (fread(lumps, 1, sizeof(lumpinfo_t)*numlumps, file) != (int)sizeof(lumpinfo_t) * numlumps)
|
||||
{Con_Printf ("W_LoadTextureWadFile: unable to read lump table");return;}
|
||||
|
||||
for (i=0, lump_p = lumps ; i<numlumps ; i++,lump_p++)
|
||||
{
|
||||
W_CleanupName (lump_p->name, lump_p->name);
|
||||
for (j = 0;j < numwadtextures;j++)
|
||||
{
|
||||
if (!strcmp(lump_p->name, texwadlump[j].name)) // name match, replace old one
|
||||
break;
|
||||
}
|
||||
if (j >= TEXWAD_MAXIMAGES)
|
||||
break; // abort loading
|
||||
if (j == numwadtextures)
|
||||
{
|
||||
W_CleanupName (lump_p->name, texwadlump[j].name);
|
||||
texwadlump[j].file = file;
|
||||
texwadlump[j].position = LittleLong(lump_p->filepos);
|
||||
texwadlump[j].size = LittleLong(lump_p->disksize);
|
||||
numwadtextures++;
|
||||
}
|
||||
}
|
||||
// leaves the file open
|
||||
}
|
||||
|
||||
/*
|
||||
void W_ApplyGamma (qbyte *data, int len, int skipalpha)
|
||||
{
|
||||
int i, inf;
|
||||
qbyte gammatable[256];
|
||||
|
||||
if (v_gamma.value == 1.0)
|
||||
{
|
||||
for (i=0 ; i<256 ; i++)
|
||||
gammatable[i] = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<256 ; i++)
|
||||
{
|
||||
inf = 255 * pow ( (i+0.5)/255.5 , v_gamma.value ) + 0.5;
|
||||
if (inf < 0)
|
||||
inf = 0;
|
||||
if (inf > 255)
|
||||
inf = 255;
|
||||
gammatable[i] = inf;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
qbyte *W_ConvertWAD3Texture(miptex_t *tex, int *width, int *height, qboolean *usesalpha) //returns rgba
|
||||
{
|
||||
qbyte *in, *data, *out, *pal;
|
||||
int d, p;
|
||||
|
||||
int alpha = 0;
|
||||
|
||||
if (tex->name[0] == '{')
|
||||
alpha = 1;
|
||||
else if (!strncmp(tex->name, "window", 6) || !strncmp(tex->name, "glass", 5))
|
||||
alpha = 2;
|
||||
|
||||
//use malloc here if you want, but you'll have to free it again... NUR!
|
||||
#ifndef SWQUAKE //quantity optimisation.
|
||||
data = out = Hunk_TempAllocMore(tex->width * tex->height * 4);
|
||||
#else
|
||||
data = out = Hunk_TempAllocMore(((tex->width*4 * tex->height) * 85)/64); //sw mip
|
||||
#endif
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
in = (qbyte *)((int) tex + tex->offsets[0]);
|
||||
|
||||
*width = tex->width;
|
||||
*height = tex->height;
|
||||
pal = in + (((tex->width * tex->height) * 85) >> 6);
|
||||
pal += 2;
|
||||
#ifndef SWQUAKE
|
||||
for (d = 0;d < tex->width * tex->height;d++)
|
||||
#else
|
||||
for (d = 0;d < (tex->width * tex->height* 85)/64;d++) //sw mip
|
||||
#endif
|
||||
{
|
||||
p = *in++;
|
||||
if (alpha==1 && p == 255) //only allow alpha on '{' textures
|
||||
out[0] = out[1] = out[2] = out[3] = 0;
|
||||
else if (alpha == 2)
|
||||
{
|
||||
p *= 3;
|
||||
out[0] = pal[p];
|
||||
out[1] = pal[p+1];
|
||||
out[2] = pal[p+2];
|
||||
out[3] = (out[0]+out[1]+out[2])/3;
|
||||
}
|
||||
else
|
||||
{
|
||||
p *= 3;
|
||||
out[0] = pal[p];
|
||||
out[1] = pal[p+1];
|
||||
out[2] = pal[p+2];
|
||||
out[3] = 255;
|
||||
}
|
||||
out += 4;
|
||||
}
|
||||
BoostGamma(data, tex->width, tex->height);
|
||||
*usesalpha = !!alpha;
|
||||
return data;
|
||||
}
|
||||
|
||||
qbyte *W_GetTexture(char *name, int *width, int *height, qboolean *usesalpha)//returns rgba
|
||||
{
|
||||
char texname[17];
|
||||
int i, j;
|
||||
FILE *file;
|
||||
miptex_t *tex;
|
||||
qbyte *data;
|
||||
|
||||
texname[16] = 0;
|
||||
W_CleanupName (name, texname);
|
||||
for (i = 0;i < numwadtextures;i++)
|
||||
{
|
||||
if (!strcmp(texname, texwadlump[i].name)) // found it
|
||||
{
|
||||
file = texwadlump[i].file;
|
||||
if (fseek(file, texwadlump[i].position, SEEK_SET))
|
||||
{Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
|
||||
|
||||
tex = BZ_Malloc(texwadlump[i].size); //temp buffer for disk info (was hunk_tempalloc, but that wiped loading maps and the like
|
||||
if (!tex)
|
||||
return NULL;
|
||||
if (fread(tex, 1, texwadlump[i].size, file) < texwadlump[i].size)
|
||||
{Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
|
||||
|
||||
tex->width = LittleLong(tex->width);
|
||||
tex->height = LittleLong(tex->height);
|
||||
for (j = 0;j < MIPLEVELS;j++)
|
||||
tex->offsets[j] = LittleLong(tex->offsets[j]);
|
||||
data = W_ConvertWAD3Texture(tex, width, height, usesalpha); //this will add to the temp
|
||||
BZ_Free(tex);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *COM_ParseToken (char *data);
|
||||
//extern model_t *loadmodel;
|
||||
|
||||
char wads[4096];
|
||||
void Mod_ParseInfoFromEntityLump(char *data) //actually, this should be in the model code.
|
||||
{
|
||||
extern model_t *loadmodel;
|
||||
char key[128];
|
||||
|
||||
wads[0] = '\0';
|
||||
|
||||
if (isDedicated) //don't bother
|
||||
return;
|
||||
|
||||
R_SetSky("", 0, r_origin);
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
if (!(data=COM_ParseToken(data))) //read the map info.
|
||||
return; // error
|
||||
if (com_token[0] != '{')
|
||||
return; // error
|
||||
while (1)
|
||||
{
|
||||
if (!(data=COM_ParseToken(data)))
|
||||
return; // error
|
||||
if (com_token[0] == '}')
|
||||
break; // end of worldspawn
|
||||
if (com_token[0] == '_')
|
||||
strcpy(key, com_token + 1); //_ vars are for comments/utility stuff that arn't visible to progs. Ignore them.
|
||||
else
|
||||
strcpy(key, com_token);
|
||||
if (!((data=COM_ParseToken(data))))
|
||||
return; // error
|
||||
if (!strcmp("wad", key)) // for HalfLife maps
|
||||
{
|
||||
if (loadmodel->fromgame == fg_halflife)
|
||||
{
|
||||
strncat(wads, ";", 4095); //cache it for later (so that we don't play with any temp memory yet)
|
||||
strncat(wads, com_token, 4095); //cache it for later (so that we don't play with any temp memory yet)
|
||||
}
|
||||
}
|
||||
else if (!strcmp("skyname", key)) // for HalfLife maps
|
||||
{
|
||||
R_SetSky(com_token, 0, r_origin);
|
||||
}
|
||||
else if (!strcmp("sky", key)) // for Quake2 maps
|
||||
{
|
||||
R_SetSky(com_token, 0, r_origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qboolean Wad_NextDownload (void)
|
||||
{
|
||||
char wadname[4096];
|
||||
int i, j, k;
|
||||
|
||||
if (*wads) //now go about checking the wads
|
||||
{
|
||||
j = 0;
|
||||
wads[4095] = '\0';
|
||||
for (i = 0;i < 4095;i++)
|
||||
if (wads[i] != ';' && wads[i] != '\\' && wads[i] != '/' && wads[i] != ':')
|
||||
break;
|
||||
if (wads[i])
|
||||
{
|
||||
j=i;
|
||||
for (;i < 4095;i++)
|
||||
{
|
||||
// ignore path...
|
||||
if (wads[i] == '\\' || wads[i] == '/' || wads[i] == ':')
|
||||
j = i+1;
|
||||
else if (wads[i] == ';' || wads[i] == 0)
|
||||
{
|
||||
k = wads[i];
|
||||
wads[i] = 0;
|
||||
strcpy(wadname, &wads[j]);
|
||||
if (*wadname)
|
||||
if (!CL_CheckOrDownloadFile(wadname, true))
|
||||
return false;
|
||||
wads[i] = k;
|
||||
|
||||
j = i+1;
|
||||
if (!k)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Wads_Flush();
|
||||
if (*wads) //now go about loading the wads, we are now safe from tempallocs
|
||||
{
|
||||
j = 0;
|
||||
wads[4095] = '\0';
|
||||
for (i = 0;i < 4095;i++)
|
||||
if (wads[i] != ';' && wads[i] != '\\' && wads[i] != '/' && wads[i] != ':')
|
||||
break;
|
||||
if (wads[i])
|
||||
{
|
||||
j=i;
|
||||
for (;i < 4095;i++)
|
||||
{
|
||||
// ignore path...
|
||||
if (wads[i] == '\\' || wads[i] == '/' || wads[i] == ':')
|
||||
j = i+1;
|
||||
else if (wads[i] == ';' || wads[i] == 0)
|
||||
{
|
||||
k = wads[i];
|
||||
wads[i] = 0;
|
||||
strcpy(wadname, &wads[j]);
|
||||
if (*wadname)
|
||||
W_LoadTextureWadFile (wadname, false);
|
||||
j = i+1;
|
||||
if (!k)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// wad.h
|
||||
|
||||
//===============
|
||||
// TYPES
|
||||
//===============
|
||||
|
||||
#define CMP_NONE 0
|
||||
#define CMP_LZSS 1
|
||||
|
||||
#define TYP_NONE 0
|
||||
#define TYP_LABEL 1
|
||||
|
||||
#define TYP_LUMPY 64 // 64 + grab command number
|
||||
#define TYP_PALETTE 64
|
||||
#define TYP_QTEX 65
|
||||
#define TYP_QPIC 66
|
||||
#define TYP_SOUND 67
|
||||
#define TYP_MIPTEX 68
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
qbyte data[4]; // variably sized
|
||||
} qpic_t;
|
||||
extern qpic_t *draw_disc; // also used on sbar
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char identification[4]; // should be WAD2 or 2DAW
|
||||
int numlumps;
|
||||
int infotableofs;
|
||||
} wadinfo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int filepos;
|
||||
int disksize;
|
||||
int size; // uncompressed
|
||||
char type;
|
||||
char compression;
|
||||
char pad1, pad2;
|
||||
char name[16]; // must be null terminated
|
||||
} lumpinfo_t;
|
||||
|
||||
extern int wad_numlumps;
|
||||
extern lumpinfo_t *wad_lumps;
|
||||
extern qbyte *wad_base;
|
||||
|
||||
void W_LoadWadFile (char *filename);
|
||||
void W_CleanupName (char *in, char *out);
|
||||
lumpinfo_t *W_GetLumpinfo (char *name);
|
||||
void *W_GetLumpName (char *name);
|
||||
void *W_SafeGetLumpName (char *name);
|
||||
void *W_GetLumpNum (int num);
|
||||
void Wads_Flush (void);
|
||||
|
||||
void SwapPic (qpic_t *pic);
|
||||
|
||||
|
||||
|
||||
void Mod_ParseWadsFromEntityLump(char *data);
|
||||
qbyte *W_ConvertWAD3Texture(miptex_t *tex, int *width, int *height, qboolean *usesalpha);
|
||||
void Mod_ParseInfoFromEntityLump(char *data);
|
||||
qboolean Wad_NextDownload (void);
|
||||
qbyte *W_GetTexture(char *name, int *width, int *height, qboolean *usesalpha);
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// winquake.h: Win32-specific Quake header file
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#if defined(_WIN32) && !defined(WIN32)
|
||||
#define WIN32 _WIN32
|
||||
#endif
|
||||
|
||||
#ifdef MSVCDISABLEWARNINGS
|
||||
#pragma warning( disable : 4229 ) // mgraph gets this
|
||||
#endif
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define byte winbyte
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <mmsystem.h>
|
||||
#define _LPCWAVEFORMATEX_DEFINED
|
||||
|
||||
|
||||
#ifndef WM_MOUSEWHEEL
|
||||
#define WM_MOUSEWHEEL 0x020A
|
||||
#endif
|
||||
|
||||
#define WM_MWHOOK (WM_USER + 1)
|
||||
|
||||
#ifndef SERVERONLY
|
||||
#ifndef NODIRECTX
|
||||
#include <ddraw.h>
|
||||
#include <dsound.h>
|
||||
#endif
|
||||
#ifdef SWQUAKE
|
||||
#ifdef MGL
|
||||
#include <mgraph.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef byte
|
||||
|
||||
extern HINSTANCE global_hInstance;
|
||||
extern int global_nCmdShow;
|
||||
|
||||
#ifndef SERVERONLY
|
||||
|
||||
#ifdef _WIN32
|
||||
LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NODIRECTX
|
||||
extern qboolean DDActive;
|
||||
extern LPDIRECTDRAW lpDD;
|
||||
extern LPDIRECTDRAWSURFACE lpPrimary;
|
||||
extern LPDIRECTDRAWSURFACE lpFrontBuffer;
|
||||
extern LPDIRECTDRAWSURFACE lpBackBuffer;
|
||||
extern LPDIRECTDRAWPALETTE lpDDPal;
|
||||
#endif
|
||||
|
||||
struct soundcardinfo_s {
|
||||
int snd_linear_count; //change in asm_i386.h. MUST be first
|
||||
|
||||
float pitch[MAXSOUNDCHANNELS];
|
||||
float yaw[MAXSOUNDCHANNELS];
|
||||
float dist[MAXSOUNDCHANNELS];
|
||||
|
||||
#ifndef NODIRECTX
|
||||
LPDIRECTSOUND pDS;
|
||||
LPDIRECTSOUNDBUFFER pDSBuf;
|
||||
LPDIRECTSOUNDBUFFER pDSPBuf;
|
||||
#endif
|
||||
HWAVEOUT hWaveOut;
|
||||
HANDLE hData;
|
||||
HGLOBAL hWaveHdr;
|
||||
HPSTR lpData;
|
||||
LPWAVEHDR lpWaveHdr;
|
||||
DWORD mmstarttime;
|
||||
DWORD gSndBufSize;
|
||||
|
||||
#ifndef NODIRECTX
|
||||
qboolean snd_isdirect;
|
||||
#endif
|
||||
qboolean snd_iswave;
|
||||
|
||||
int paintedtime;
|
||||
int oldpaintedtime;
|
||||
int oldsamplepos;
|
||||
int buffers;
|
||||
|
||||
#ifndef NODIRECTX
|
||||
qboolean dsound_init;
|
||||
#endif
|
||||
qboolean wav_init;
|
||||
|
||||
dma_t sn;
|
||||
|
||||
|
||||
char name[128];
|
||||
|
||||
int snd_sent;
|
||||
int snd_completed;
|
||||
|
||||
channel_t channel[MAX_CHANNELS];
|
||||
int total_chans;
|
||||
|
||||
#ifndef NODIRECTX
|
||||
#ifdef _IKsPropertySet_
|
||||
LPKSPROPERTYSET EaxKsPropertiesSet;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int rawstart;
|
||||
int rawend;
|
||||
|
||||
struct soundcardinfo_s *next;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//void VID_LockBuffer (void);
|
||||
//void VID_UnlockBuffer (void);
|
||||
|
||||
#endif
|
||||
|
||||
extern HWND mainwindow;
|
||||
extern qboolean ActiveApp, Minimized;
|
||||
|
||||
extern qboolean WinNT;
|
||||
|
||||
void IN_ShowMouse (void);
|
||||
void IN_DeactivateMouse (void);
|
||||
void IN_HideMouse (void);
|
||||
void IN_ActivateMouse (void);
|
||||
void IN_RestoreOriginalMouseState (void);
|
||||
void IN_SetQuakeMouseState (void);
|
||||
void IN_MouseEvent (int mstate);
|
||||
|
||||
extern qboolean winsock_lib_initialized;
|
||||
|
||||
extern int window_center_x, window_center_y;
|
||||
extern RECT window_rect;
|
||||
|
||||
extern qboolean mouseinitialized;
|
||||
extern HWND hwnd_dialog;
|
||||
|
||||
//extern HANDLE hinput, houtput;
|
||||
|
||||
void IN_UpdateClipCursor (void);
|
||||
void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify);
|
||||
int MapKey (int key);
|
||||
void MW_Hook_Message (long buttons);
|
||||
|
||||
void S_BlockSound (void);
|
||||
void S_UnblockSound (void);
|
||||
|
||||
void VID_SetDefaultMode (void);
|
||||
|
||||
int (PASCAL FAR *pWSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData);
|
||||
int (PASCAL FAR *pWSACleanup)(void);
|
||||
int (PASCAL FAR *pWSAGetLastError)(void);
|
||||
SOCKET (PASCAL FAR *psocket)(int af, int type, int protocol);
|
||||
int (PASCAL FAR *pioctlsocket)(SOCKET s, long cmd, u_long FAR *argp);
|
||||
int (PASCAL FAR *psetsockopt)(SOCKET s, int level, int optname,
|
||||
const char FAR * optval, int optlen);
|
||||
int (PASCAL FAR *precvfrom)(SOCKET s, char FAR * buf, int len, int flags,
|
||||
struct sockaddr FAR *from, int FAR * fromlen);
|
||||
int (PASCAL FAR *psendto)(SOCKET s, const char FAR * buf, int len, int flags,
|
||||
const struct sockaddr FAR *to, int tolen);
|
||||
int (PASCAL FAR *pclosesocket)(SOCKET s);
|
||||
int (PASCAL FAR *pgethostname)(char FAR * name, int namelen);
|
||||
struct hostent FAR * (PASCAL FAR *pgethostbyname)(const char FAR * name);
|
||||
struct hostent FAR * (PASCAL FAR *pgethostbyaddr)(const char FAR * addr,
|
||||
int len, int type);
|
||||
int (PASCAL FAR *pgetsockname)(SOCKET s, struct sockaddr FAR *name,
|
||||
int FAR * namelen);
|
||||
#endif
|
|
@ -0,0 +1,127 @@
|
|||
//Microsoft Developer Studio generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
#if defined(APSTUDIO_INVOKED) || defined(BRAINS)
|
||||
#if defined(APSTUDIO_INVOKED)
|
||||
IDI_ICON2$(BRAINS) ICON DISCARDABLE "qwcl2.ico"
|
||||
#else
|
||||
IDI_ICON2 ICON DISCARDABLE "qwcl2.ico"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_DIALOG1 DIALOGEX 0, 0, 67, 40
|
||||
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_POPUP |
|
||||
WS_VISIBLE
|
||||
EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE
|
||||
FONT 16, "Times New Roman"
|
||||
BEGIN
|
||||
CTEXT "FTE QuakeWorld",IDC_STATIC,0,0,67,21,SS_CENTERIMAGE
|
||||
CTEXT "Frilly Tin Elephants",IDC_STATIC,0,23,66,17,
|
||||
SS_CENTERIMAGE
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
BEGIN
|
||||
IDS_STRING1 "WinQuake"
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.K.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON1 ICON DISCARDABLE "q2.ico"
|
||||
#endif // English (U.K.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// console
|
||||
//
|
||||
|
||||
#define MAXCONCOLOURS 8
|
||||
typedef struct {
|
||||
float r, g, b;
|
||||
int pal;
|
||||
} consolecolours_t;
|
||||
extern consolecolours_t consolecolours[MAXCONCOLOURS];
|
||||
|
||||
#define CON_STANDARDMASK 0x0080
|
||||
#define CON_COLOURMASK 0x0700
|
||||
#define CON_SPAREMASK3 0x0800 //something cool?
|
||||
#define CON_SPAREMASK2 0x1000 //underline?
|
||||
#define CON_SPAREMASK1 0x2000 //italics?
|
||||
#define CON_BLINKTEXT 0x4000
|
||||
#define CON_2NDCHARSETTEXT 0x8000
|
||||
|
||||
#define COLOR_WHITE '0'
|
||||
#define COLOR_RED '1'
|
||||
#define COLOR_GREEN '2'
|
||||
#define COLOR_YELLOW '3'
|
||||
#define COLOR_BLUE '4'
|
||||
#define COLOR_CYAN '5'
|
||||
#define COLOR_MAGENTA '6'
|
||||
#define COLOR_BLACK '7'
|
||||
|
||||
#define S_COLOR_WHITE "^0" //q3 uses 7. Fix some time?
|
||||
#define S_COLOR_RED "^1"
|
||||
#define S_COLOR_GREEN "^2"
|
||||
#define S_COLOR_YELLOW "^3"
|
||||
#define S_COLOR_BLUE "^4"
|
||||
#define S_COLOR_CYAN "^5"
|
||||
#define S_COLOR_MAGENTA "^6"
|
||||
#define S_COLOR_BLACK "^7" //q3 uses 0
|
||||
|
||||
#define CON_TEXTSIZE 16384
|
||||
typedef struct
|
||||
{
|
||||
unsigned short text[CON_TEXTSIZE];
|
||||
int current; // line where next message will be printed
|
||||
int x; // offset in current line for next print
|
||||
int display; // bottom of console displays this line
|
||||
int linewidth;
|
||||
int totallines;
|
||||
int vislines;
|
||||
void (*redirect) (int key);
|
||||
} console_t;
|
||||
|
||||
extern console_t con_main;
|
||||
extern console_t *con; // point to either con_main or con_chat
|
||||
|
||||
extern int con_ormask;
|
||||
|
||||
//extern int con_totallines;
|
||||
extern qboolean con_initialized;
|
||||
extern qbyte *con_chars;
|
||||
extern int con_notifylines; // scan lines to clear for notify lines
|
||||
|
||||
extern qboolean con_debuglog;
|
||||
|
||||
void Con_DrawCharacter (int cx, int line, int num);
|
||||
|
||||
void Con_CheckResize (void);
|
||||
void Con_Init (void);
|
||||
void Con_DrawConsole (int lines, qboolean noback);
|
||||
void Con_Print (char *txt);
|
||||
void Con_CycleConsole (void);
|
||||
void VARGS Con_Printf (const char *fmt, ...);
|
||||
void VARGS Con_TPrintf (translation_t text, ...);
|
||||
void VARGS Con_DPrintf (char *fmt, ...);
|
||||
void VARGS Con_SafePrintf (char *fmt, ...);
|
||||
void Con_Clear_f (void);
|
||||
void Con_DrawNotify (void);
|
||||
void Con_ClearNotify (void);
|
||||
void Con_ToggleConsole_f (void);
|
||||
|
||||
void Con_NotifyBox (char *text); // during startup for sound / cd warnings
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef _PARTICLES_H_
|
||||
#define _PARTICLES_H_
|
||||
|
||||
extern int pt_explosion,
|
||||
pt_emp,
|
||||
pt_pointfile,
|
||||
pt_entityparticles,
|
||||
pt_darkfield,
|
||||
pt_blob,
|
||||
pt_blood,
|
||||
pt_lightningblood,
|
||||
pt_gunshot,
|
||||
pt_wizspike,
|
||||
pt_knightspike,
|
||||
pt_spike,
|
||||
pt_superspike,
|
||||
pt_lavasplash,
|
||||
pt_teleportsplash,
|
||||
pt_blasterparticles,
|
||||
pt_torch,
|
||||
pt_flame,
|
||||
pt_bullet,
|
||||
pt_superbullet,
|
||||
pe_default;
|
||||
|
||||
extern int rt_rocket_trail,
|
||||
rt_smoke,
|
||||
rt_blood,
|
||||
rt_tracer,
|
||||
rt_slight_blood,
|
||||
rt_tracer2,
|
||||
rt_voor_trail,
|
||||
rt_fireball,
|
||||
rt_ice,
|
||||
rt_spit,
|
||||
rt_spell,
|
||||
rt_vorpal,
|
||||
rt_setstaff,
|
||||
rt_magicmissile,
|
||||
rt_boneshard,
|
||||
rt_scarab,
|
||||
rt_acidball,
|
||||
rt_bloodshot,
|
||||
rt_blastertrail,
|
||||
rt_railtrail,
|
||||
rt_bubbletrail;
|
||||
|
||||
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
|
||||
typedef struct particle_s
|
||||
{
|
||||
// driver-usable fields
|
||||
vec3_t org;
|
||||
float color;
|
||||
vec3_t rgb;
|
||||
float alpha;
|
||||
|
||||
// drivers never touch the following fields
|
||||
vec3_t vel;
|
||||
struct particle_s *next;
|
||||
float nextemit;
|
||||
float die;
|
||||
|
||||
float scale;
|
||||
|
||||
} particle_t;
|
||||
|
||||
#define PARTICLE_Z_CLIP 8.0
|
||||
|
||||
#define frandom() (rand()*(1.0f/RAND_MAX))
|
||||
#define crandom() (rand()*(2.0f/RAND_MAX)-1.0f)
|
||||
#define hrandom() (rand()*(1.0f/RAND_MAX)-0.5f)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,773 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// protocol.h -- communications protocols
|
||||
#define PEXT_SETVIEW 0x00000001
|
||||
|
||||
#define PEXT_SCALE 0x00000002
|
||||
#define PEXT_LIGHTSTYLECOL 0x00000004
|
||||
#define PEXT_TRANS 0x00000008
|
||||
#ifdef SIDEVIEWS
|
||||
#define PEXT_VIEW2 0x00000010
|
||||
#endif
|
||||
#define PEXT_BULLETENS 0x00000020
|
||||
#ifdef AVAIL_ZLIB
|
||||
// #define PEXT_ZLIBDL 0x00000040
|
||||
#endif
|
||||
//#define PEXT_LIGHTUPDATES 0x00000080 //send progs/zap.mdl in the same mannor as a nail.
|
||||
#define PEXT_FATNESS 0x00000100 //GL only (or servers)
|
||||
#define PEXT_HLBSP 0x00000200
|
||||
#define PEXT_TE_BULLET 0x00000400
|
||||
#define PEXT_HULLSIZE 0x00000800
|
||||
#define PEXT_MODELDBL 0x00001000
|
||||
#define PEXT_ENTITYDBL 0x00002000 //max of 1024 ents instead of 512
|
||||
#define PEXT_ENTITYDBL2 0x00004000 //max of 1024 ents instead of 512
|
||||
//#define PEXT_ORIGINDBL 0x00008000 //max of +-8192 instead of +-4096 of map origins (Achieved by *2 on origins in writecoord)
|
||||
#define PEXT_VWEAP 0x00010000 //cause an extra qbyte to be sent, and an extra list of models for vweaps.
|
||||
#ifdef Q2BSPS
|
||||
#define PEXT_Q2BSP 0x00020000
|
||||
#endif
|
||||
#ifdef Q3BSPS
|
||||
#define PEXT_Q3BSP 0x00040000
|
||||
#endif
|
||||
#define PEXT_SEEF1 0x00080000
|
||||
#define PEXT_SPLITSCREEN 0x00100000
|
||||
#define PEXT_HEXEN2 0x00200000
|
||||
#define PEXT_SPAWNSTATIC2 0x00400000 //Sends an entity delta instead of a baseline.
|
||||
#define PEXT_CUSTOMTEMPEFFECTS 0x00800000 //supports custom temp ents.
|
||||
#define PEXT_256PACKETENTITIES 0x01000000 //Client can recieve 256 packet entities.
|
||||
//#define PEXT_64PLAYERS 0x02000000 //Client is able to cope with 64 players. Wow.
|
||||
|
||||
|
||||
|
||||
//ZQuake transparent protocol extensions.
|
||||
#define Z_EXT_PM_TYPE (1<<0) // basic PM_TYPE functionality (reliable jump_held)
|
||||
#define Z_EXT_PM_TYPE_NEW (1<<1) // adds PM_FLY, PM_SPECTATOR
|
||||
#define Z_EXT_VIEWHEIGHT (1<<2) // STAT_VIEWHEIGHT
|
||||
#define Z_EXT_SERVERTIME (1<<3) // STAT_TIME
|
||||
#define Z_EXT_PITCHLIMITS (1<<4) // serverinfo maxpitch & minpitch
|
||||
#define Z_EXT_JOIN_OBSERVE (1<<5) // server: "join" and "observe" commands are supported
|
||||
// client: on-the-fly spectator <-> player switching supported
|
||||
#define SUPPORTED_EXTENSIONS (Z_EXT_PM_TYPE|Z_EXT_PM_TYPE_NEW|Z_EXT_VIEWHEIGHT|Z_EXT_SERVERTIME|Z_EXT_PITCHLIMITS|Z_EXT_JOIN_OBSERVE)
|
||||
|
||||
|
||||
#define PROTOCOL_VERSION_FTE (('F'<<0) + ('T'<<8) + ('E'<<16) + ('X' << 24)) //fte extensions.
|
||||
#define PROTOCOL_VERSION_HUFFMAN (('H'<<0) + ('U'<<8) + ('F'<<16) + ('F' << 24)) //packet compression
|
||||
|
||||
#define PROTOCOL_VERSION 28
|
||||
#define PROTOCOL_VERSION_Q2_MIN 31
|
||||
#define PROTOCOL_VERSION_Q2 34
|
||||
|
||||
//=========================================
|
||||
|
||||
#define PORT_CLIENT 27001
|
||||
#define PORT_MASTER 27000
|
||||
#define PORT_SERVER 27500
|
||||
#define Q2PORT_CLIENT 27901
|
||||
#define Q2PORT_SERVER 27910
|
||||
|
||||
//=========================================
|
||||
|
||||
// out of band message id bytes
|
||||
|
||||
// M = master, S = server, C = client, A = any
|
||||
// the second character will allways be \n if the message isn't a single
|
||||
// qbyte long (?? not true anymore?)
|
||||
|
||||
#define S2C_CHALLENGE 'c'
|
||||
#define S2C_CONNECTION 'j'
|
||||
#define A2A_PING 'k' // respond with an A2A_ACK
|
||||
#define A2A_ACK 'l' // general acknowledgement without info
|
||||
#define A2A_NACK 'm' // [+ comment] general failure
|
||||
#define A2A_ECHO 'e' // for echoing
|
||||
#define A2C_PRINT 'n' // print a message on client
|
||||
|
||||
#define S2M_HEARTBEAT 'a' // + serverinfo + userlist + fraglist
|
||||
#define A2C_CLIENT_COMMAND 'B' // + command line
|
||||
#define S2M_SHUTDOWN 'C'
|
||||
|
||||
#define M2C_MASTER_REPLY 'd' // + \n + qw server port list
|
||||
//==================
|
||||
// note that there are some defs.qc that mirror to these numbers
|
||||
// also related to svc_strings[] in cl_parse
|
||||
//==================
|
||||
|
||||
//
|
||||
// server to client
|
||||
//
|
||||
#define svc_bad 0
|
||||
#define svc_nop 1
|
||||
#define svc_disconnect 2
|
||||
#define svc_updatestat 3 // [qbyte] [qbyte]
|
||||
#define svc_version 4 // [long] server version
|
||||
#define svc_setview 5 // [short] entity number
|
||||
#define svc_sound 6 // <see code>
|
||||
#define svc_time 7 // [float] server time
|
||||
#define svc_print 8 // [qbyte] id [string] null terminated string
|
||||
#define svc_stufftext 9 // [string] stuffed into client's console buffer
|
||||
// the string should be \n terminated
|
||||
#define svc_setangle 10 // [angle3] set the view angle to this absolute value
|
||||
|
||||
#define svc_serverdata 11 // [long] protocol ...
|
||||
#define svc_lightstyle 12 // [qbyte] [string]
|
||||
#define svc_updatename 13 // [qbyte] [string]
|
||||
#define svc_updatefrags 14 // [qbyte] [short]
|
||||
#define svc_clientdata 15 // <shortbits + data>
|
||||
#define svc_stopsound 16 // <see code>
|
||||
#define svc_updatecolors 17 // [qbyte] [qbyte] [qbyte]
|
||||
#define svc_particle 18 // [vec3] <variable>
|
||||
#define svc_damage 19
|
||||
|
||||
#define svc_spawnstatic 20
|
||||
#define svc_spawnstatic2 21
|
||||
#define svc_spawnbaseline 22
|
||||
|
||||
#define svc_temp_entity 23 // variable
|
||||
#define svc_setpause 24 // [qbyte] on / off
|
||||
#define svc_signonnum 25 // [qbyte] used for the signon sequence
|
||||
|
||||
#define svc_centerprint 26 // [string] to put in center of the screen
|
||||
|
||||
#define svc_killedmonster 27
|
||||
#define svc_foundsecret 28
|
||||
|
||||
#define svc_spawnstaticsound 29 // [coord3] [qbyte] samp [qbyte] vol [qbyte] aten
|
||||
|
||||
#define svc_intermission 30 // [vec3_t] origin [vec3_t] angle
|
||||
#define svc_finale 31 // [string] text
|
||||
|
||||
#define svc_cdtrack 32 // [qbyte] track
|
||||
#define svc_sellscreen 33
|
||||
|
||||
#define svc_cutscene 34 //hmm... nq only... added after qw tree splitt?
|
||||
|
||||
#define svc_smallkick 34 // set client punchangle to 2
|
||||
#define svc_bigkick 35 // set client punchangle to 4
|
||||
|
||||
#define svc_updateping 36 // [qbyte] [short]
|
||||
#define svc_updateentertime 37 // [qbyte] [float]
|
||||
|
||||
#define svc_updatestatlong 38 // [qbyte] [long]
|
||||
|
||||
#define svc_muzzleflash 39 // [short] entity
|
||||
|
||||
#define svc_updateuserinfo 40 // [qbyte] slot [long] uid
|
||||
// [string] userinfo
|
||||
|
||||
#define svc_download 41 // [short] size [size bytes]
|
||||
#define svc_playerinfo 42 // variable
|
||||
#define svc_nails 43 // [qbyte] num [48 bits] xyzpy 12 12 12 4 8
|
||||
#define svc_chokecount 44 // [qbyte] packets choked
|
||||
#define svc_modellist 45 // [strings]
|
||||
#define svc_soundlist 46 // [strings]
|
||||
#define svc_packetentities 47 // [...]
|
||||
#define svc_deltapacketentities 48 // [...]
|
||||
#define svc_maxspeed 49 // maxspeed change, for prediction
|
||||
#define svc_entgravity 50 // gravity change, for prediction
|
||||
#define svc_setinfo 51 // setinfo on a client
|
||||
#define svc_serverinfo 52 // serverinfo
|
||||
#define svc_updatepl 53 // [qbyte] [qbyte]
|
||||
|
||||
#define svc_nails2 54 //qwe - [qbyte] num [52 bits] nxyzpy 8 12 12 12 4 8
|
||||
|
||||
|
||||
#ifdef PEXT_VIEW2
|
||||
#define svc_view2 56
|
||||
#endif
|
||||
#ifdef PEXT_LIGHTSTYLECOL
|
||||
#define svc_lightstylecol 57
|
||||
#endif
|
||||
|
||||
#ifdef PEXT_BULLETENS
|
||||
#define svc_bulletentext 58
|
||||
#endif
|
||||
|
||||
#ifdef PEXT_LIGHTUPDATES
|
||||
#define svc_lightnings 59
|
||||
#endif
|
||||
|
||||
#ifdef PEXT_MODELDBL
|
||||
#define svc_modellistshort 60 // [strings]
|
||||
#endif
|
||||
|
||||
#define svc_ftesetclientpersist 61 //ushort DATA
|
||||
|
||||
#define svc_setportalstate 62
|
||||
|
||||
#define svc_particle2 63
|
||||
#define svc_particle3 64
|
||||
#define svc_particle4 65
|
||||
#define svc_spawnbaseline2 66
|
||||
|
||||
#define svc_customtempent 67
|
||||
|
||||
#define svc_choosesplitclient 68
|
||||
|
||||
#define svc_invalid 256
|
||||
|
||||
|
||||
enum svcq2_ops_e
|
||||
{
|
||||
svcq2_bad, //0
|
||||
|
||||
// these ops are known to the game dll
|
||||
svcq2_muzzleflash, //1
|
||||
svcq2_muzzleflash2, //2
|
||||
svcq2_temp_entity, //3
|
||||
svcq2_layout, //4
|
||||
svcq2_inventory, //5
|
||||
|
||||
// the rest are private to the client and server
|
||||
svcq2_nop, //6
|
||||
svcq2_disconnect, //7
|
||||
svcq2_reconnect, //8
|
||||
svcq2_sound, //9 // <see code>
|
||||
svcq2_print, //10 // [qbyte] id [string] null terminated string
|
||||
svcq2_stufftext, //11 // [string] stuffed into client's console buffer, should be \n terminated
|
||||
svcq2_serverdata, //12 // [long] protocol ...
|
||||
svcq2_configstring, //13 // [short] [string]
|
||||
svcq2_spawnbaseline,//14
|
||||
svcq2_centerprint, //15 // [string] to put in center of the screen
|
||||
svcq2_download, //16 // [short] size [size bytes]
|
||||
svcq2_playerinfo, //17 // variable
|
||||
svcq2_packetentities,//18 // [...]
|
||||
svcq2_deltapacketentities,//19 // [...]
|
||||
svcq2_frame //20 (the bastard to implement.)
|
||||
};
|
||||
|
||||
enum clcq2_ops_e
|
||||
{
|
||||
clcq2_bad,
|
||||
clcq2_nop,
|
||||
clcq2_move, // [[usercmd_t]
|
||||
clcq2_userinfo, // [[userinfo string]
|
||||
clcq2_stringcmd // [string] message
|
||||
};
|
||||
|
||||
|
||||
//==============================================
|
||||
|
||||
//
|
||||
// client to server
|
||||
//
|
||||
#define clc_bad 0
|
||||
#define clc_nop 1
|
||||
#define clc_disconnect 2 //nq only
|
||||
#define clc_move 3 // [[usercmd_t]
|
||||
#define clc_stringcmd 4 // [string] message
|
||||
#define clc_delta 5 // [qbyte] sequence number, requests delta compression of message
|
||||
#define clc_tmove 6 // teleport request, spectator only
|
||||
#define clc_upload 7 // teleport request, spectator only
|
||||
|
||||
|
||||
//==============================================
|
||||
|
||||
// playerinfo flags from server
|
||||
// playerinfo allways sends: playernum, flags, origin[] and framenumber
|
||||
|
||||
#define PF_MSEC (1<<0)
|
||||
#define PF_COMMAND (1<<1)
|
||||
#define PF_VELOCITY1 (1<<2)
|
||||
#define PF_VELOCITY2 (1<<3)
|
||||
#define PF_VELOCITY3 (1<<4)
|
||||
#define PF_MODEL (1<<5)
|
||||
#define PF_SKINNUM (1<<6)
|
||||
#define PF_EFFECTS (1<<7)
|
||||
#define PF_WEAPONFRAME (1<<8) // only sent for view player
|
||||
#define PF_DEAD (1<<9) // don't block movement any more
|
||||
#define PF_GIB (1<<10) // offset the view height differently
|
||||
|
||||
//ZQuake.
|
||||
#define PF_PMC_MASK ((1<<11) +\
|
||||
(1<<12) +\
|
||||
(1<<13))
|
||||
|
||||
#define PF_EXTRA_PFS (1<<15)
|
||||
|
||||
//FIXME: Resolve this.
|
||||
|
||||
// bits 11..13 are player move type bits
|
||||
|
||||
#ifdef PEXT_SCALE
|
||||
#define PF_SCALE_NOZ (1<<12)
|
||||
#define PF_SCALE_Z (1<<16)
|
||||
#endif
|
||||
#ifdef PEXT_TRANS
|
||||
#define PF_TRANS_NOZ (1<<13)
|
||||
#define PF_TRANS_Z (1<<17)
|
||||
#endif
|
||||
#ifdef PEXT_FATNESS
|
||||
#define PF_FATNESS_NOZ (1<<14)
|
||||
#define PF_FATNESS_Z (1<<18)
|
||||
#endif
|
||||
#ifdef PEXT_HULLSIZE
|
||||
#define PF_HULLSIZE_NOZ (1<<15)
|
||||
#define PF_HULLSIZE_Z (1<<14)
|
||||
#endif
|
||||
|
||||
#define PF_ORIGINDBL (1<<19)
|
||||
|
||||
|
||||
|
||||
#define PF_PMC_SHIFT 11
|
||||
|
||||
|
||||
|
||||
// player move types
|
||||
#define PMC_NORMAL 0 // normal ground movement
|
||||
#define PMC_NORMAL_JUMP_HELD 1 // normal ground novement + jump_held
|
||||
#define PMC_OLD_SPECTATOR 2 // fly through walls (QW compatibility mode)
|
||||
#define PMC_SPECTATOR 3 // fly through walls
|
||||
#define PMC_FLY 4 // fly, bump into walls
|
||||
#define PMC_NONE 5 // can't move (client had better lerp the origin...)
|
||||
#define PMC_FREEZE 6 // TODO: lerp movement and viewangles
|
||||
#define PMC_EXTRA3 7 // future extension
|
||||
|
||||
//any more will require a different protocol message.
|
||||
|
||||
//==============================================
|
||||
|
||||
// if the high bit of the client to server qbyte is set, the low bits are
|
||||
// client move cmd bits
|
||||
// ms and angle2 are allways sent, the others are optional
|
||||
#define CM_ANGLE1 (1<<0)
|
||||
#define CM_ANGLE3 (1<<1)
|
||||
#define CM_FORWARD (1<<2)
|
||||
#define CM_SIDE (1<<3)
|
||||
#define CM_UP (1<<4)
|
||||
#define CM_BUTTONS (1<<5)
|
||||
#define CM_IMPULSE (1<<6)
|
||||
#define CM_ANGLE2 (1<<7)
|
||||
|
||||
//sigh...
|
||||
#define Q2CM_ANGLE1 (1<<0)
|
||||
#define Q2CM_ANGLE2 (1<<1)
|
||||
#define Q2CM_ANGLE3 (1<<2)
|
||||
#define Q2CM_FORWARD (1<<3)
|
||||
#define Q2CM_SIDE (1<<4)
|
||||
#define Q2CM_UP (1<<5)
|
||||
#define Q2CM_BUTTONS (1<<6)
|
||||
#define Q2CM_IMPULSE (1<<7)
|
||||
|
||||
//==============================================
|
||||
|
||||
// the first 16 bits of a packetentities update holds 9 bits
|
||||
// of entity number and 7 bits of flags
|
||||
#define U_ORIGIN1 (1<<9)
|
||||
#define U_ORIGIN2 (1<<10)
|
||||
#define U_ORIGIN3 (1<<11)
|
||||
#define U_ANGLE2 (1<<12)
|
||||
#define U_FRAME (1<<13)
|
||||
#define U_REMOVE (1<<14) // REMOVE this entity, don't add it
|
||||
#define U_MOREBITS (1<<15)
|
||||
|
||||
// if MOREBITS is set, these additional flags are read in next
|
||||
#define U_ANGLE1 (1<<0)
|
||||
#define U_ANGLE3 (1<<1)
|
||||
#define U_MODEL (1<<2)
|
||||
#define U_COLORMAP (1<<3)
|
||||
#define U_SKIN (1<<4)
|
||||
#define U_EFFECTS (1<<5)
|
||||
#define U_SOLID (1<<6) // the entity should be solid for prediction
|
||||
#ifdef PROTOCOLEXTENSIONS
|
||||
#define U_EVENMORE (1<<7) //extension info follows
|
||||
|
||||
//fte extensions
|
||||
//EVENMORE flags
|
||||
#ifdef PEXT_SCALE
|
||||
#define U_SCALE (1<<0) //scaler of alias models
|
||||
#endif
|
||||
#ifdef PEXT_TRANS
|
||||
#define U_TRANS (1<<1) //transparency value
|
||||
#endif
|
||||
#ifdef PEXT_FATNESS
|
||||
#define U_FATNESS (1<<2) //qbyte describing how fat an alias model should be. (moves verticies along normals). Useful for vacuum chambers...
|
||||
#endif
|
||||
#ifdef PEXT_MODELDBL
|
||||
#define U_MODELDBL (1<<3) //extra bit for modelindexes
|
||||
#endif
|
||||
//FIXME: IMPLEMENT
|
||||
#ifdef PEXT_ENTITYDBL
|
||||
#define U_ENTITYDBL (1<<5) //use an extra qbyte for origin parts, cos one of them is off
|
||||
#endif
|
||||
#ifdef PEXT_ENTITYDBL2
|
||||
#define U_ENTITYDBL2 (1<<6) //use an extra qbyte for origin parts, cos one of them is off
|
||||
#endif
|
||||
#define U_YETMORE (1<<7) //even more extension info stuff.
|
||||
|
||||
#define U_DRAWFLAGS (1<<8) //use an extra qbyte for origin parts, cos one of them is off
|
||||
#define U_ABSLIGHT (1<<9) //Force a lightlevel
|
||||
|
||||
#ifdef PEXT_BIGORIGINS
|
||||
#define U_ORIGINDBL (1<<10) //use an extra qbyte for origin parts, cos one of them is off
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define Q2U_ORIGIN1 (1<<0)
|
||||
#define Q2U_ORIGIN2 (1<<1)
|
||||
#define Q2U_ANGLE2 (1<<2)
|
||||
#define Q2U_ANGLE3 (1<<3)
|
||||
#define Q2U_FRAME8 (1<<4) // frame is a qbyte
|
||||
#define Q2U_EVENT (1<<5)
|
||||
#define Q2U_REMOVE (1<<6) // REMOVE this entity, don't add it
|
||||
#define Q2U_MOREBITS1 (1<<7) // read one additional qbyte
|
||||
|
||||
// second qbyte
|
||||
#define Q2U_NUMBER16 (1<<8) // NUMBER8 is implicit if not set
|
||||
#define Q2U_ORIGIN3 (1<<9)
|
||||
#define Q2U_ANGLE1 (1<<10)
|
||||
#define Q2U_MODEL (1<<11)
|
||||
#define Q2U_RENDERFX8 (1<<12) // fullbright, etc
|
||||
#define Q2U_EFFECTS8 (1<<14) // autorotate, trails, etc
|
||||
#define Q2U_MOREBITS2 (1<<15) // read one additional qbyte
|
||||
|
||||
// third qbyte
|
||||
#define Q2U_SKIN8 (1<<16)
|
||||
#define Q2U_FRAME16 (1<<17) // frame is a short
|
||||
#define Q2U_RENDERFX16 (1<<18) // 8 + 16 = 32
|
||||
#define Q2U_EFFECTS16 (1<<19) // 8 + 16 = 32
|
||||
#define Q2U_MODEL2 (1<<20) // weapons, flags, etc
|
||||
#define Q2U_MODEL3 (1<<21)
|
||||
#define Q2U_MODEL4 (1<<22)
|
||||
#define Q2U_MOREBITS3 (1<<23) // read one additional qbyte
|
||||
|
||||
// fourth qbyte
|
||||
#define Q2U_OLDORIGIN (1<<24) // FIXME: get rid of this
|
||||
#define Q2U_SKIN16 (1<<25)
|
||||
#define Q2U_SOUND (1<<26)
|
||||
#define Q2U_SOLID (1<<27)
|
||||
|
||||
//==============================================
|
||||
|
||||
// a sound with no channel is a local only sound
|
||||
// the sound field has bits 0-2: channel, 3-12: entity
|
||||
#define SND_VOLUME (1<<15) // a qbyte
|
||||
#define SND_ATTENUATION (1<<14) // a qbyte
|
||||
|
||||
#define DEFAULT_SOUND_PACKET_VOLUME 255
|
||||
#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
|
||||
|
||||
|
||||
#define DEFAULT_VIEWHEIGHT 22
|
||||
|
||||
|
||||
// svc_print messages have an id, so messages can be filtered
|
||||
#define PRINT_LOW 0
|
||||
#define PRINT_MEDIUM 1
|
||||
#define PRINT_HIGH 2
|
||||
#define PRINT_CHAT 3 // also go to chat buffer
|
||||
|
||||
//
|
||||
// temp entity events
|
||||
//
|
||||
enum {
|
||||
TE_SPIKE = 0,
|
||||
TE_SUPERSPIKE = 1,
|
||||
TE_GUNSHOT = 2,
|
||||
TE_EXPLOSION = 3,
|
||||
TE_TAREXPLOSION = 4,
|
||||
TE_LIGHTNING1 = 5,
|
||||
TE_LIGHTNING2 = 6,
|
||||
TE_WIZSPIKE = 7,
|
||||
TE_KNIGHTSPIKE = 8,
|
||||
TE_LIGHTNING3 = 9,
|
||||
TE_LAVASPLASH = 10,
|
||||
TE_TELEPORT = 11,
|
||||
|
||||
TE_BLOOD = 12,
|
||||
TE_LIGHTNINGBLOOD = 13,
|
||||
|
||||
#ifdef PEXT_TE_BULLET
|
||||
TE_BULLET = 14,
|
||||
TE_SUPERBULLET = 15,
|
||||
#endif
|
||||
|
||||
TE_RAILTRAIL = 17,
|
||||
|
||||
// hexen 2
|
||||
TE_STREAM_CHAIN = 25,
|
||||
TE_STREAM_SUNSTAFF1 = 26,
|
||||
TE_STREAM_SUNSTAFF2 = 27,
|
||||
TE_STREAM_LIGHTNING = 28,
|
||||
TE_STREAM_COLORBEAM = 29,
|
||||
TE_STREAM_ICECHUNKS = 30,
|
||||
TE_STREAM_GAZE = 31,
|
||||
TE_STREAM_FAMINE = 32,
|
||||
|
||||
TE_BIGGRENADE = 33,
|
||||
TE_CHUNK = 34,
|
||||
TE_HWBONEPOWER = 35,
|
||||
TE_HWBONEPOWER2 = 36,
|
||||
TE_METEORHIT = 37,
|
||||
TE_HWRAVENDIE = 38,
|
||||
TE_HWRAVENEXPLODE = 39,
|
||||
TE_XBOWHIT = 40,
|
||||
|
||||
TE_CHUNK2 = 41,
|
||||
TE_ICEHIT = 42,
|
||||
TE_ICESTORM = 43,
|
||||
TE_HWMISSILEFLASH = 44,
|
||||
TE_SUNSTAFF_CHEAP = 45,
|
||||
TE_LIGHTNING_HAMMER = 46,
|
||||
TE_DRILLA_EXPLODE = 47,
|
||||
TE_DRILLA_DRILL = 48,
|
||||
|
||||
TE_HWTELEPORT = 49,
|
||||
TE_SWORD_EXPLOSION = 50,
|
||||
|
||||
TE_AXE_BOUNCE = 51,
|
||||
TE_AXE_EXPLODE = 52,
|
||||
TE_TIME_BOMB = 53,
|
||||
TE_FIREBALL = 54,
|
||||
TE_SUNSTAFF_POWER = 55,
|
||||
TE_PURIFY2_EXPLODE = 56,
|
||||
TE_PLAYER_DEATH = 57,
|
||||
TE_PURIFY1_EFFECT = 58,
|
||||
TE_TELEPORT_LINGER = 59,
|
||||
TE_LINE_EXPLOSION = 60,
|
||||
TE_METEOR_CRUSH = 61,
|
||||
//MISSION PACK
|
||||
TE_STREAM_LIGHTNING_SMALL = 62,
|
||||
|
||||
TE_ACIDBALL = 63,
|
||||
TE_ACIDBLOB = 64,
|
||||
TE_FIREWALL = 65,
|
||||
TE_FIREWALL_IMPACT = 66,
|
||||
TE_HWBONERIC = 67,
|
||||
TE_POWERFLAME = 68,
|
||||
TE_BLOODRAIN = 69,
|
||||
TE_AXE = 70,
|
||||
TE_PURIFY2_MISSILE = 71,
|
||||
TE_SWORD_SHOT = 72,
|
||||
TE_ICESHOT = 73,
|
||||
TE_METEOR = 74,
|
||||
TE_LIGHTNINGBALL = 75,
|
||||
TE_MEGAMETEOR = 76,
|
||||
TE_CUBEBEAM = 77,
|
||||
TE_LIGHTNINGEXPLODE = 78,
|
||||
TE_ACID_BALL_FLY = 79,
|
||||
TE_ACID_BLOB_FLY = 80,
|
||||
TE_CHAINLIGHTNING = 81
|
||||
};
|
||||
|
||||
#define NQTE_EXPLOSION2 12
|
||||
#define NQTE_BEAM 13
|
||||
|
||||
|
||||
#define TE_SEEF_BRIGHTFIELD 200
|
||||
#define TE_SEEF_DARKLIGHT 201
|
||||
#define TE_SEEF_DARKFIELD 202
|
||||
#define TE_SEEF_LIGHT 203
|
||||
|
||||
|
||||
/*
|
||||
==========================================================
|
||||
|
||||
ELEMENTS COMMUNICATED ACROSS THE NET
|
||||
|
||||
==========================================================
|
||||
*/
|
||||
|
||||
#define MAX_CLIENTS 32
|
||||
|
||||
#define UPDATE_BACKUP 64 // copies of entity_state_t to keep buffered
|
||||
// must be power of two
|
||||
#define UPDATE_MASK (UPDATE_BACKUP-1)
|
||||
|
||||
#define Q2UPDATE_BACKUP 16 // copies of entity_state_t to keep buffered
|
||||
// must be power of two
|
||||
#define Q2UPDATE_MASK (Q2UPDATE_BACKUP-1)
|
||||
|
||||
// entity_state_t is the information conveyed from the server
|
||||
// in an update message
|
||||
|
||||
//FIXME: split the q2 vars.
|
||||
#ifdef SERVERONLY
|
||||
typedef struct entity_state_s
|
||||
{
|
||||
int number; // edict index
|
||||
|
||||
int flags; // nolerp, etc
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
int modelindex;
|
||||
int frame;
|
||||
int colormap;
|
||||
int skinnum;
|
||||
int effects;
|
||||
|
||||
#ifdef PEXT_SCALE
|
||||
float scale;
|
||||
#endif
|
||||
#ifdef PEXT_TRANS
|
||||
float trans;
|
||||
#endif
|
||||
#ifdef PEXT_FATNESS
|
||||
float fatness;
|
||||
#endif
|
||||
|
||||
int drawflags;
|
||||
int abslight;
|
||||
} entity_state_t;
|
||||
#else
|
||||
typedef struct entity_state_s
|
||||
{
|
||||
int number; // edict index
|
||||
|
||||
int flags; // nolerp, etc
|
||||
vec3_t origin;
|
||||
vec3_t old_origin; //q2
|
||||
vec3_t angles;
|
||||
int modelindex;
|
||||
int modelindex2; //q2
|
||||
int modelindex3; //q2
|
||||
int modelindex4; //q2
|
||||
int frame;
|
||||
int colormap;
|
||||
int skinnum;
|
||||
int effects;
|
||||
int renderfx; //q2
|
||||
int sound; //q2
|
||||
int event; //q2
|
||||
|
||||
int solid;
|
||||
|
||||
#ifdef PEXT_SCALE
|
||||
float scale;
|
||||
#endif
|
||||
#ifdef PEXT_TRANS
|
||||
float trans;
|
||||
#endif
|
||||
#ifdef PEXT_FATNESS
|
||||
float fatness;
|
||||
#endif
|
||||
int drawflags;
|
||||
int abslight;
|
||||
} entity_state_t;
|
||||
#endif
|
||||
|
||||
#define MAX_EXTENDED_PACKET_ENTITIES 256 //sanity limit.
|
||||
#define MAX_STANDARD_PACKET_ENTITIES 64 // doesn't count nails
|
||||
#define MAX_MVDPACKET_ENTITIES 196 // doesn't count nails
|
||||
typedef struct
|
||||
{
|
||||
int num_entities;
|
||||
int max_entities;
|
||||
entity_state_t *entities;
|
||||
} packet_entities_t;
|
||||
|
||||
typedef struct usercmd_s
|
||||
{
|
||||
qbyte msec;
|
||||
qbyte buttons;
|
||||
short angles[3];
|
||||
short forwardmove, sidemove, upmove;
|
||||
qbyte impulse;
|
||||
qbyte lightlevel;
|
||||
} usercmd_t;
|
||||
#define SHORT2ANGLE(x) (x) * (360.0/65536)
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// per-level limits
|
||||
//
|
||||
#define Q2MAX_CLIENTS 256 // absolute limit
|
||||
#define Q2MAX_EDICTS 1024 // must change protocol to increase more
|
||||
#define Q2MAX_LIGHTSTYLES 256
|
||||
#define Q2MAX_MODELS 256 // these are sent over the net as bytes
|
||||
#define Q2MAX_SOUNDS 256 // so they cannot be blindly increased
|
||||
#define Q2MAX_IMAGES 256
|
||||
#define Q2MAX_ITEMS 256
|
||||
#define Q2MAX_GENERAL (Q2MAX_CLIENTS*2) // general config strings
|
||||
|
||||
|
||||
#define Q2CS_NAME 0
|
||||
#define Q2CS_CDTRACK 1
|
||||
#define Q2CS_SKY 2
|
||||
#define Q2CS_SKYAXIS 3 // %f %f %f format
|
||||
#define Q2CS_SKYROTATE 4
|
||||
#define Q2CS_STATUSBAR 5 // display program string
|
||||
|
||||
#define Q2CS_AIRACCEL 29 // air acceleration control
|
||||
#define Q2CS_MAXCLIENTS 30
|
||||
#define Q2CS_MAPCHECKSUM 31 // for catching cheater maps
|
||||
|
||||
#define Q2CS_MODELS 32
|
||||
#define Q2CS_SOUNDS (Q2CS_MODELS +Q2MAX_MODELS)
|
||||
#define Q2CS_IMAGES (Q2CS_SOUNDS +Q2MAX_SOUNDS)
|
||||
#define Q2CS_LIGHTS (Q2CS_IMAGES +Q2MAX_IMAGES)
|
||||
#define Q2CS_ITEMS (Q2CS_LIGHTS +Q2MAX_LIGHTSTYLES)
|
||||
#define Q2CS_PLAYERSKINS (Q2CS_ITEMS +Q2MAX_ITEMS)
|
||||
#define Q2CS_GENERAL (Q2CS_PLAYERSKINS +Q2MAX_CLIENTS)
|
||||
#define Q2MAX_CONFIGSTRINGS (Q2CS_GENERAL +Q2MAX_GENERAL)
|
||||
|
||||
|
||||
// player_state->stats[] indexes
|
||||
#define Q2STAT_HEALTH_ICON 0
|
||||
#define Q2STAT_HEALTH 1
|
||||
#define Q2STAT_AMMO_ICON 2
|
||||
#define Q2STAT_AMMO 3
|
||||
#define Q2STAT_ARMOR_ICON 4
|
||||
#define Q2STAT_ARMOR 5
|
||||
#define Q2STAT_SELECTED_ICON 6
|
||||
#define Q2STAT_PICKUP_ICON 7
|
||||
#define Q2STAT_PICKUP_STRING 8
|
||||
#define Q2STAT_TIMER_ICON 9
|
||||
#define Q2STAT_TIMER 10
|
||||
#define Q2STAT_HELPICON 11
|
||||
#define Q2STAT_SELECTED_ITEM 12
|
||||
#define Q2STAT_LAYOUTS 13
|
||||
#define Q2STAT_FRAGS 14
|
||||
#define Q2STAT_FLASHES 15 // cleared each frame, 1 = health, 2 = armor
|
||||
#define Q2STAT_CHASE 16
|
||||
#define Q2STAT_SPECTATOR 17
|
||||
|
||||
#define Q2MAX_STATS 32
|
||||
|
||||
|
||||
|
||||
// edict->drawflags
|
||||
#define MLS_MASKIN 7 // Model Light Style
|
||||
#define MLS_MASKOUT 248
|
||||
#define MLS_NONE 0
|
||||
#define MLS_FULLBRIGHT 1
|
||||
#define MLS_POWERMODE 2
|
||||
#define MLS_TORCH 3
|
||||
#define MLS_TOTALDARK 4
|
||||
#define MLS_ABSLIGHT 7
|
||||
#define SCALE_TYPE_MASKIN 24
|
||||
#define SCALE_TYPE_MASKOUT 231
|
||||
#define SCALE_TYPE_UNIFORM 0 // Scale X, Y, and Z
|
||||
#define SCALE_TYPE_XYONLY 8 // Scale X and Y
|
||||
#define SCALE_TYPE_ZONLY 16 // Scale Z
|
||||
#define SCALE_ORIGIN_MASKIN 96
|
||||
#define SCALE_ORIGIN_MASKOUT 159
|
||||
#define SCALE_ORIGIN_CENTER 0 // Scaling origin at object center
|
||||
#define SCALE_ORIGIN_BOTTOM 32 // Scaling origin at object bottom
|
||||
#define SCALE_ORIGIN_TOP 64 // Scaling origin at object top
|
||||
#define DRF_TRANSLUCENT 128
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sys.h -- non-portable functions
|
||||
|
||||
//
|
||||
// file IO
|
||||
//
|
||||
|
||||
// returns the file size
|
||||
// return -1 if file is not present
|
||||
// the file should be in BINARY mode for stupid OSs that care
|
||||
int Sys_FileOpenRead (char *path, int *hndl);
|
||||
|
||||
int Sys_FileOpenWrite (char *path);
|
||||
void Sys_FileClose (int handle);
|
||||
void Sys_FileSeek (int handle, int position);
|
||||
int Sys_FileRead (int handle, void *dest, int count);
|
||||
int Sys_FileWrite (int handle, void *data, int count);
|
||||
int Sys_FileTime (char *path);
|
||||
void Sys_mkdir (char *path);
|
||||
qboolean Sys_remove (char *path);
|
||||
|
||||
//
|
||||
// memory protection
|
||||
//
|
||||
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
|
||||
|
||||
//
|
||||
// system IO
|
||||
//
|
||||
void VARGS Sys_DebugLog(char *file, char *fmt, ...);
|
||||
|
||||
void VARGS Sys_Error (const char *error, ...);
|
||||
// an error will cause the entire program to exit
|
||||
|
||||
void VARGS Sys_Printf (char *fmt, ...);
|
||||
// send text to the console
|
||||
|
||||
void Sys_Quit (void);
|
||||
|
||||
double Sys_DoubleTime (void);
|
||||
|
||||
char *Sys_ConsoleInput (void);
|
||||
|
||||
//stuff for dynamic dedicated console -> gfx and back.
|
||||
void Sys_CloseTerminal (void);
|
||||
qboolean Sys_InitTerminal (void);
|
||||
void Con_PrintToSys(void);
|
||||
|
||||
void Sys_Sleep (void);
|
||||
// called to yield for a little bit so as
|
||||
// not to hog cpu when paused or debugging
|
||||
|
||||
void Sys_SendKeyEvents (void);
|
||||
// Perform Key_Event () callbacks until the input que is empty
|
||||
|
||||
void Sys_LowFPPrecision (void);
|
||||
void Sys_HighFPPrecision (void);
|
||||
void VARGS Sys_SetFPCW (void);
|
||||
|
||||
int Sys_EnumerateFiles (char *gpath, char *match, int (*func)(char *, int, void *), void *parm);
|
||||
|
||||
#ifdef _WIN32
|
||||
int StartLocalServer(int close);
|
||||
#endif
|
||||
|
||||
void Sys_Init (void);
|
|
@ -0,0 +1,832 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
#undef malloc
|
||||
#undef free
|
||||
|
||||
static char *defaultlanguagetext =
|
||||
"STL_LANGUAGENAME \"English\"\n"
|
||||
"TL_NL \"\\n\"\n"
|
||||
"TL_ST \"%s\"\n"
|
||||
"TL_STNL \"%s\\n\"\n"
|
||||
"STL_CLIENTCONNECTED \"client %s connected\\n\"\n"
|
||||
"STL_SPECTATORCONNECTED \"spectator %s connected\\n\"\n"
|
||||
"STL_RECORDEDCLIENTCONNECTED \"recorded client %s connected\\n\"\n"
|
||||
"STL_RECORDEDSPECTATORCONNECTED \"recorded spectator %s connected\\n\"\n"
|
||||
"STL_CLIENTWASBANNED \"%s was banned\\n\"\n"
|
||||
"STL_YOUWEREBANNED \"You were banned\\n\"\n"
|
||||
"STL_YOUAREBANNED \"You are still banned\\n\"\n"
|
||||
"STL_CLIENTTIMEDOUT \"Client %s timed out\\n\"\n"
|
||||
"STL_LOADZOMIBETIMEDOUT \"LoadZombie %s timed out\\n\"\n"
|
||||
"STL_CLIENTWASKICKED \"%s was kicked\\n\"\n"
|
||||
"STL_YOUWEREKICKED \"You were kicked\\n\"\n"
|
||||
"STL_YOUWEREKICKEDNAMESPAM \"You were kicked for name spamming\\n\"\n"
|
||||
"STL_CLIENTKICKEDNAMESPAM \"%s was kicked for name spamming\\n\"\n"
|
||||
"STL_GODON \"godmode ON\\n\"\n"
|
||||
"STL_GODOFF \"godmode OFF\\n\"\n"
|
||||
"STL_NOCLIPON \"noclip ON\\n\"\n"
|
||||
"STL_NOCLIPOFF \"noclip OFF\"\n"
|
||||
"STL_CLIENTISCUFFEDPERMANENTLY \"%s is still cuffed\\n\"\n"
|
||||
"STL_CLIENTISCUFFED \"%s is was cuffed\\n\"\n"
|
||||
"STL_CLIENTISSTILLCUFFED \"%s is still cuffed\\n\"\n"
|
||||
"STL_YOUWERECUFFED \"You were cuffed\\n\"\n"
|
||||
"STL_YOUARNTCUFFED \"You are no longer cuffed\\n\"\n"
|
||||
"STL_CLIENTISCRIPPLEDPERMANENTLY \"%s is now crippled permanently\\n\"\n"
|
||||
"STL_CLIENTISCRIPPLED \"%s is crippled\\n\"\n"
|
||||
"STL_CLIENTISSTILLCRIPPLED \"%s is still crippled\\n\"\n"
|
||||
"STL_YOUWERECLIPPLED \"You have been crippled\\n\"\n"
|
||||
"STL_YOUARNTCRIPPLED \"You are no longer crippled\\n\"\n"
|
||||
"STL_CLIENTISMUTEDPERMANENTLY \"%s was muted permanently\\n\"\n"
|
||||
"STL_CLIENTISMUTED \"%s was muted\\n\"\n"
|
||||
"STL_CLIENTISSTILLMUTED \"%s is muted (still)\\n\"\n"
|
||||
"STL_YOUAREMUTED \"%s is muted\\n\"\n"
|
||||
"STL_YOUARNTMUTED \"You are no longer muted\\n\"\n"
|
||||
"STL_NONAMEASMUTE \"Muted players may not change thier names\\n\"\n"
|
||||
"STL_MUTEDVOTE \"Sorry, you cannot vote when muted as it may allow you to send a message.\\n\"\n"
|
||||
"STL_MUTEDCHAT \"You cannot chat while muted\\n\"\n"
|
||||
"STL_FLOODPROTACTIVE \"floodprot: You can't talk for %i seconds\\n\"\n"
|
||||
"STL_FLOODPROTTIME \"You can't talk for %i more seconds\\n\"\n"
|
||||
"STL_BUFFERPROTECTION \"buffer overflow protection: failiure\\n\"\n"
|
||||
"STL_FIRSTGREETING \"Welcome %s. Your time on this server is being logged and ranked\\n\"\n"
|
||||
"STL_SHORTGREETING \"Welcome back %s. You have previously spent %i mins connected\\n\"\n"
|
||||
"STL_BIGGREETING \"Welcome back %s. You have previously spent %i:%i hours connected\\n\"\n"
|
||||
"STL_POSSIBLEMODELCHEAT \"warning: %s eyes or player model does not match\\n\"\n"
|
||||
"STL_MAPCHEAT \"Map model file does not match (%s), %i != %i/%i.\\nYou may need a new version of the map, or the proper install files.\\n\"\n"
|
||||
"STL_INVALIDTRACKCLIENT \"invalid player to track\\n\"\n"
|
||||
"STL_BADNAME \"Can't change name - new is invalid\\n\"\n"
|
||||
"STL_CLIENTNAMECHANGE \"%s changed thier name to %s\\n\"\n"
|
||||
"STL_SERVERPAUSED \"server is paused\\n\"\n"
|
||||
"STL_UPLOADDENIED \"Upload denied\\n\"\n"
|
||||
"STL_NAMEDCLIENTDOESNTEXIST \"client does not exist\\n\"\n"
|
||||
"STL_NOSUISIDEWHENDEAD \"Can't suiside -- Already dead\\n\"\n"
|
||||
"STL_CANTPAUSE \"Can't pause. Not allowed\\n\"\n"
|
||||
"STL_CANTPAUSESPEC \"Spectators may not pause the game\\n\"\n"
|
||||
"STL_CLIENTPAUSED \"%s paused the game\\n\"\n"
|
||||
"STL_CLIENTUNPAUSED \"%s unpaused the game\\n\"\n"
|
||||
"STL_CLIENTLESSUNPAUSE \"pause released due to empty server\\n\"\n"
|
||||
"STL_CURRENTRATE \"current rate is %i\\n\"\n"
|
||||
"STL_RATESETTO \"rate is changed to %i\\n\"\n"
|
||||
"STL_CURRENTMSGLEVEL \"current msg level is %i\\n\"\n"
|
||||
"STL_MSGLEVELSET \"new msg level set to %i\\n\"\n"
|
||||
"STL_GAMESAVED \"Server has saved the game\\n\"\n"
|
||||
"STL_CLIENTDROPPED \"%s dropped\\n\"\n"
|
||||
"STL_SNAPREFUSED \"%s refused remote screenshot\\n\"\n"
|
||||
"STL_FINALVOTE \"%s casts final vote for '%s'\\n\"\n"
|
||||
"STL_VOTE \"%s casts a vote for '%s'\\n\"\n"
|
||||
"STL_SPEEDCHEATKICKED \"%s was kicked for speedcheating (%s)\\n\"\n"
|
||||
"STL_SPEEDCHEATPOSSIBLE \"Speed cheat possibility, analyzing:\\n %d %.1f %d for: %s\\n\"\n"
|
||||
"STL_INITED \"======== FTE QuakeWorld Initialized ========\\n\"\n"
|
||||
"STL_BACKBUFSET \"WARNING %s: [SV_New] Back buffered (%d0, clearing)\\n\"\n"
|
||||
"STL_MESSAGEOVERFLOW \"WARNING: backbuf [%d] reliable overflow for %s\\n\"\n"
|
||||
"STL_BUILDINGPHS \"Building PHS...\\n\"\n"
|
||||
"STL_PHSINFO \"Average leafs visible / hearable / total: %i / %i / %i\\n\"\n"
|
||||
"STL_BREAKSTATEMENT \"Break Statement\\n\"\n"
|
||||
"STL_BADSPRINT \"tried to sprint to a non-client\\n\"\n"
|
||||
"STL_NOPRECACHE \"no precache: %s\\n\"\n"
|
||||
"STL_CANTFREEWORLD \"cannot free world entity\\n\"\n"
|
||||
"STL_CANTFREEPLAYERS \"cannot free player entities\\n\"\n"
|
||||
"STL_COMPILEROVER \"Compile took %f secs\\n\"\n"
|
||||
"STL_EDICTWASFREE \"%s edict was free\\n\"\n"
|
||||
"STL_NOFREEEDICTS \"WARNING: no free edicts\\n\"\n"
|
||||
"STL_NEEDCHEATPARM \"You must run the server with -cheats to enable this command.\\n\"\n"
|
||||
"STL_USERDOESNTEXIST \"Couldn't find user number %s\\n\"\n"
|
||||
"STL_MAPCOMMANDUSAGE \"map <levelname> : continue game on a new level\\n\"\n"
|
||||
"STL_NOVOTING \"Voting was dissallowed\\n\"\n"
|
||||
"STL_BADVOTE \"You arn't allowed to vote for that\\n\"\n"
|
||||
"STL_VOTESREMOVED \"All votes removed.\\n\"\n"
|
||||
"STL_OLDVOTEREMOVED \"Old vote removed.\\n\"\n"
|
||||
"TL_EXECING \"execing %s\\n\"\n"
|
||||
"TL_EXECCOMMANDUSAGE \"exec <filename> : execute a script file\\n\"\n"
|
||||
"TL_EXECFAILED \"couldn't exec %s\\n\"\n"
|
||||
"TL_FUNCOVERFLOW \"%s: overflow\\n\"\n"
|
||||
"TL_CURRENTALIASCOMMANDS \"Current alias commands:\\n\"\n"
|
||||
"TL_ALIASNAMETOOLONG \"Alias name is too long\\n\"\n"
|
||||
"TL_ALIASRESTRICTIONLEVELERROR \"Alias is already bound with a higher restriction\\n\"\n"
|
||||
"TL_ALIASLEVELCOMMANDUSAGE \"aliaslevel <var> [execlevel]\\n\"\n"
|
||||
"TL_ALIASNOTFOUND \"Alias not found\\n\"\n"
|
||||
"TL_ALIASRAISELEVELERROR \"You arn't allowed to raise a command above your own level\\n\"\n"
|
||||
"TL_ALIASRESTRICTIONLEVELWARN \"WARNING: %s is available to all clients, any client will be able to use it at the new level.\\n\"\n"
|
||||
"TL_ALIASRESTRICTLEVEL \"alias %s is set to run at the user level of %i\\n\"\n"
|
||||
"TL_ALIASLIST \"Alias list:\\n\"\n"
|
||||
"TL_COMMANDLISTHEADER \"Command list:\\n\"\n"
|
||||
"TL_CVARLISTHEADER \"CVar list:\\n\"\n"
|
||||
"TL_RESTRICTCOMMANDRAISE \"You arn't allowed to raise a command above your own level\\n\"\n"
|
||||
"TL_RESTRICTCOMMANDTOOHIGH \"You arn't allowed to alter a level above your own\\n\"\n"
|
||||
"TL_RESTRICTCURRENTLEVEL \"%s is restricted to %i\\n\"\n"
|
||||
"TL_RESTRICTCURRENTLEVELDEFAULT \"%s is restricted to rcon_level (%i)\\n\"\n"
|
||||
"TL_RESTRICTNOTDEFINED \"restrict: %s not defined\\n\"\n"
|
||||
"TL_WASRESTIRCTED \"%s was restricted.\\n\"\n"
|
||||
"TL_COMMANDNOTDEFINED \"Unknown command \\\"%s\\\"\\n\"\n"
|
||||
"TL_IFSYNTAX \"if <condition> <statement> [elseif <condition> <statement>] [...] [else <statement>]\\n\"\n"
|
||||
"TL_IFSYNTAXERROR \"Not terminated\\n\"\n"
|
||||
"TL_SETSYNTAX \"set <var> <equation>\\n\"\n"
|
||||
"TL_CANTXNOTCONNECTED \"Can't \\\"%s\\\", not connected\\n\"\n"
|
||||
"TL_SHAREWAREVERSION \"Playing shareware version.\\n\"\n"
|
||||
"TL_REGISTEREDVERSION \"Playing registered version.\\n\"\n"
|
||||
"TL_CURRENTSEARCHPATH \"Current search path:\\n\"\n"
|
||||
"TL_SERACHPATHISPACK \"%s (%i files)\\n\"\n"
|
||||
"TL_SERACHPATHISZIP \"%s (%i files)\\n\"\n"
|
||||
"TL_COMPRESSEDFILEOPENFAILED \"Tried opening a handle to a compressed stream - %s\\n\"\n"
|
||||
"TL_ADDEDPACKFILE \"Added packfile %s (%i files)\\n\"\n"
|
||||
"TL_COULDNTOPENZIP \"Failed opening zipfile \\\"%s\\\" corrupt?\\n\"\n"
|
||||
"TL_ADDEDZIPFILE \"Added zipfile %s (%i files)\\n\"\n"
|
||||
"TL_GAMEDIRAINTPATH \"Gamedir should be a single filename, not a path\\n\"\n"
|
||||
"TL_KEYHASSLASH \"Can't use a key with a \\\\\\n\"\n"
|
||||
"TL_KEYHASQUOTE \"Can't use a key with a \\\"\\n\"\n"
|
||||
"TL_KEYTOOLONG \"Keys and values must be < 64 characters.\\n\"\n"
|
||||
"TL_INFOSTRINGTOOLONG \"Info string length exceeded\\n\"\n"
|
||||
"TL_STARKEYPROTECTED \"Can't set * keys\\n\"\n"
|
||||
"TL_KEYHASNOVALUE \"MISSING VALUE\\n\"\n"
|
||||
"TL_OVERSIZEPACKETFROM \"Warning: Oversize packet from %s\\n\"\n"
|
||||
"TL_CONNECTIONLOSTORABORTED \"Connection lost or aborted\\n\"\n"
|
||||
"TL_NETGETPACKETERROR \"NET_GetPacket: %s\\n\"\n"
|
||||
"TL_NETSENDERROR \"NET_SendPacket ERROR: %i\\n\"\n"
|
||||
"TL_NETBINDINTERFACE \"Binding to IP Interface Address of %s\\n\"\n"
|
||||
"TL_IPADDRESSIS \"IP address %s\\n\"\n"
|
||||
"TL_UDPINITED \"UDP Initialized\\n\"\n"
|
||||
"TL_SERVERPORTINITED \"Server port Initialized\\n\"\n"
|
||||
"TL_CLIENTPORTINITED \"Client port Initialized\\n\"\n"
|
||||
"TL_OUTMESSAGEOVERFLOW \"%s:Outgoing message overflow\\n\"\n"
|
||||
"TL_OUTOFORDERPACKET \"%s:Out of order packet %i at %i\\n\"\n"
|
||||
"TL_DROPPEDPACKETCOUNT \"%s:Dropped %i packets at %i\\n\"\n"
|
||||
"STL_SERVERUNSPAWNED \"Server ended\\n\"\n"
|
||||
"STL_SERVERSPAWNED \"Server spawned.\\n\"\n"
|
||||
"TL_EXEDATETIME \"Exe: %s %s\\n\"\n"
|
||||
"TL_HEAPSIZE \"%4.1f megs RAM available.\\n\"\n"
|
||||
"TL_VERSION2 \"\\nVersion %4.2f (Build %04d)\\n\\n\"\n"
|
||||
"TL_SERVERVERSION2 \"\\n%s Version %4.2f (Build %04d)\\n\\n\"\n"
|
||||
"STL_SAVESYNTAX \"save <savename> : save a game\\n\"\n"
|
||||
"STL_NORELATIVEPATHS \"Relative pathnames are not allowed.\\n\"\n"
|
||||
"STL_SAVEGAMETO \"Saving game to %s...\\n\"\n"
|
||||
"STL_ERRORCOULDNTOPEN \"ERROR: couldn't open.\\n\"\n"
|
||||
"STL_SAVEDONE \"done.\\n\"\n"
|
||||
"STL_LOADSYNTAX \"load <savename> : load a game\\n\"\n"
|
||||
"STL_LOADGAMEFROM \"Loading game from %s...\\n\"\n"
|
||||
"STL_BADSAVEVERSION \"Savegame is version %i, not %i\\n\"\n"
|
||||
"STL_LOADFAILED \"Couldn't load map\\n\"\n"
|
||||
"STL_NOMASTERMODE \"Setting nomaster mode.\\n\"\n"
|
||||
"STL_MASTERAT \"Master server at %s\\n\"\n"
|
||||
"STL_SENDINGPING \"Sending a ping.\\n\"\n"
|
||||
"STL_SHUTTINGDOWN \"Shutting down.\\n\"\n"
|
||||
"STL_LOGGINGOFF \"File logging off.\\n\"\n"
|
||||
"STL_LOGGINGTO \"Logging text to %s.\\n\"\n"
|
||||
"STL_FLOGGINGOFF \"Frag file logging off.\\n\"\n"
|
||||
"STL_FLOGGINGFAILED \"Can't open any logfiles.\\n\"\n"
|
||||
"STL_FLOGGINGTO \"Logging frags to %s.\\n\"\n"
|
||||
"STL_USERIDNOTONSERVER \"Userid %i is not on the server\\n\"\n"
|
||||
"STL_CANTFINDMAP \"Can't find %s\\n\"\n"
|
||||
"STL_SERVERINFOSETTINGS \"Server info settings:\\n\"\n"
|
||||
"STL_SERVERINFOSYNTAX \"usage: serverinfo [ <key> <value> ]\\n\"\n"
|
||||
"STL_LOCALINFOSETTINGS \"Local info settings:\\n\"\n"
|
||||
"STL_LOCALINFOSYNTAX \"usage: localinfo [ <key> <value> ]\\n\"\n"
|
||||
"STL_USERINFOSYNTAX \"Usage: info <userid>\\n\"\n"
|
||||
"STL_FLOODPROTSETTINGS \"Current floodprot settings: \\nAfter %d msgs per %d seconds, silence for %d seconds\\n\"\n"
|
||||
"STL_FLOODPROTNOTON \"No floodprots enabled.\\n\"\n"
|
||||
"STL_FLOODPROTSYNTAX \"Usage: floodprot <# of messages> <per # of seconds> <seconds to silence>\\nUse floodprotmsg to set a custom message to say to the flooder.\\n\"\n"
|
||||
"STL_NONEGATIVEVALUES \"All values must be positive numbers\\n\"\n"
|
||||
"STL_TRACK10PLUSSMESSAGES \"Can only track up to 10 messages.\\n\"\n"
|
||||
"STL_FLOODPROTCURRENTMESSAGE \"Current msg: %s\\n\"\n"
|
||||
"STL_FLOODPROTMESSAGESYNTAX \"Usage: floodprotmsg \\\"<message>\\\"\\n\"\n"
|
||||
"STL_CURRENTGAMEDIR \"Current gamedir: %s\\n\"\n"
|
||||
"STL_SVGAMEDIRUSAGE \"Usage: sv_gamedir <newgamedir>\\n\"\n"
|
||||
"STL_GAMEDIRCANTBEPATH \"*Gamedir should be a single filename, not a path\\n\"\n"
|
||||
"STL_GAMEDIRUSAGE \"Usage: gamedir <newgamedir>\\n\"\n"
|
||||
"STL_SNAPTOOMANYFILES \"Snap: Couldn't create a file, clean some out.\\n\"\n"
|
||||
"STL_SNAPREQUEST \"Requesting snap from user %d...\\n\"\n"
|
||||
"STL_SNAPUSAGE \"Usage: snap <userid>\\n\"\n"
|
||||
"TLC_VERSIONST3 \"Version %s %4.3f (Build %i)\\n\"\n"
|
||||
"TLC_VERSIONST2 \"Version %s %4.2f (Build %i)\\n\"\n"
|
||||
"TLC_VERSION2 \"Version %4.2f (Build %i)\\n\"\n"
|
||||
"TLC_BADSERVERADDRESS \"Bad server address\\n\"\n"
|
||||
"TLC_ILLEGALSERVERADDRESS \"Illegal server address\\n\"\n"
|
||||
"TLC_CONNECTINGTO \"Connecting to %s...\\n\"\n"
|
||||
"TLC_SYNTAX_CONNECT \"usage: connect <server>\\n\"\n"
|
||||
"TLC_NORCONPASSWORD \"You must set 'rcon_password' before\\nissuing an rcon command.\\n\"\n"
|
||||
"TLC_NORCONDEST \"You must either be connected,\\nor set the 'rcon_address' cvar\\nto issue rcon commands\\n\"\n"
|
||||
"TLC_SYNTAX_USER \"Usage: user <username / userid>\\n\"\n"
|
||||
"TLC_USER_NOUSER \"User not in server.\\n\"\n"
|
||||
"TLC_USERBANNER \"userid frags name\\n\"\n"
|
||||
"TLC_USERBANNER2 \"------ ----- ----\\n\"\n"
|
||||
"TLC_USERLINE \"%6i %4i %s\\n\"\n"
|
||||
"TLC_USERTOTAL \"%i total users\\n\"\n"
|
||||
"TLC_COLOURCURRENT \"\\\"color\\\" is \\\"%s %s\\\"\\n\"\n"
|
||||
"TLC_SYNTAX_COLOUR \"color <0-13> [0-13]\\n\"\n"
|
||||
"TLC_SYNTAX_FULLSERVERINFO \"usage: fullserverinfo <complete info string>\\n\"\n"
|
||||
"TLC_SERVER_VERSION \"Version %1.2f Server\\n\"\n"
|
||||
"TLC_SYNTAX_FULLINFO \"fullinfo <complete info string>\\n\"\n"
|
||||
"TLC_SYNTAX_SETINFO \"usage: setinfo [ <key> <value> ]\\n\"\n"
|
||||
"TLC_PACKET_SYNTAX \"packet <destination> <contents>\\n\"\n"
|
||||
"TLC_BADADDRESS \"Bad address\\n\"\n"
|
||||
"TLC_CHANGINGMAP \"\\nChanging map...\\n\"\n"
|
||||
"TLC_RECONNECTING \"reconnecting...\\n\"\n"
|
||||
"TLC_RECONNECT_NOSERVER \"No server to reconnect to...\\n\"\n"
|
||||
"TL_ST_COLON \"%s: \"\n"
|
||||
"TLC_GOTCONNECTION \"connection\\n\"\n"
|
||||
"TLC_DUPCONNECTION \"Dup connect received. Ignored.\\n\"\n"
|
||||
"TLC_CONNECTED \"Connected.\\n\"\n"
|
||||
"TLC_CONLESS_CONCMD \"client command\\n\"\n"
|
||||
"TLC_CMDFROMREMOTE \"Command packet from remote host. Ignored.\\n\"\n"
|
||||
"TL_LINEBREAK_EQUALS \"===========================\\n\"\n"
|
||||
"TLC_LOCALID_NOTSET \"Command packet received from local host, but no localid has been set. You may need to upgrade your server browser.\\n\"\n"
|
||||
"TLC_LOCALID_BAD \"Invalid localid on command packet received from local host. \\n|%s| != |%s|\\nYou may need to reload your server browser and QuakeWorld.\\n\"\n"
|
||||
"TLC_A2C_PRINT \"print\\n\"\n"
|
||||
"TLC_A2A_PING \"ping\\n\"\n"
|
||||
"TLC_S2C_CHALLENGE \"challenge\\n\"\n"
|
||||
"TLC_CONLESSPACKET_UNKNOWN \"unknown connectionless packet: %c\\n\"\n"
|
||||
"TL_RUNTPACKET \"%s: Runt packet\\n\"\n"
|
||||
"TLC_SERVERTIMEOUT \"\\nServer connection timed out.\\n\"\n"
|
||||
"TLC_CONNECTFIRST \"Must be connected.\\n\"\n"
|
||||
"TLC_SYNTAX_DOWNLOAD \"Usage: download <datafile>\\n\"\n"
|
||||
"TLC_REQUIRESSERVERMOD \"%s is only available with server support\\n\"\n"
|
||||
"TLC_CLIENTCON_ERROR_ENDGAME \"Host_EndGame: %s\\n\"\n"
|
||||
"TLC_HOSTFATALERROR \"Host_Error: %s\\n\"\n"
|
||||
"TLC_CONFIGCFG_WRITEFAILED \"Couldn't write config.cfg.\\n\"\n"
|
||||
"TLC_HOSTSPEEDSOUTPUT \"%3i tot %3i server %3i gfx %3i snd\\n\"\n"
|
||||
"TLC_QUAKEWORLD_INITED \"€<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> QuakeWorld Initialized <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>‚\\n\"\n"
|
||||
"TLC_DEDICATEDCANNOTCONNECT \"Connect ignored - dedicated. set a renderer first\\n\"\n"
|
||||
"TLC_Q2CONLESSPACKET_UNKNOWN \"unknown connectionless packet for q2: %s\\n\"\n"
|
||||
"TL_NORELATIVEPATHS \"Refusing to download a path with ..\\n\"\n"
|
||||
"TL_NODOWNLOADINDEMO \"Unable to download %s in record mode.\\n\"\n"
|
||||
"TL_DOWNLOADINGFILE \"Downloading %s...\\n\"\n"
|
||||
"TLC_CHECKINGMODELS \"Checking models...\\n\"\n"
|
||||
"TLC_CHECKINGSOUNDS \"Checking sounds...\\n\"\n"
|
||||
"TL_FILENOTFOUND \"File not found.\\n\"\n"
|
||||
"TL_CLS_DOWNLOAD_ISSET \"cls.download shouldn't have been set\\n\"\n"
|
||||
"TL_FAILEDTOOPEN \"Failed to open %s\\n\"\n"
|
||||
"TL_RENAMEFAILED \"failed to rename.\\n\"\n"
|
||||
"TL_UPLOADCOMPLEATE \"Upload completed\\n\"\n"
|
||||
"TL_FTEEXTENSIONS \"Using FTE extensions 0x%x\\n\"\n"
|
||||
"TLC_LINEBREAK_NEWLEVEL \"\\n\\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\\n\\n\"\n"
|
||||
"TLC_PC_PS_NL \"%c%s\\n\"\n"
|
||||
"TLC_NOQ2CINEMATICSSUPPORT \"Cinematics on q2 levels is not yet supported\\nType 'cmd nextserver %i' to proceed.\"\n"
|
||||
"TLC_GOTSVDATAPACKET \"Serverdata packet received.\\n\"\n"
|
||||
"TLC_BAD_MAXCLIENTS \"Bad maxclients from server\\n\"\n"
|
||||
"TLC_TOOMANYMODELPRECACHES \"Server sent too many model precaches\\n\"\n"
|
||||
"TLC_TOOMANYSOUNDPRECACHES \"Server sent too many sound precaches\\n\"\n"
|
||||
"TLC_PARSESTATICWITHNOMAP \"Warning: Parsestatic and no map loaded yet\\n\"\n"
|
||||
"TL_FILE_X_MISSING \"\\nThe required model file '%s' could not be found or downloaded.\\n\\n\"\n"
|
||||
"TL_GETACLIENTPACK \"You may need to download or purchase a %s client or map pack in order to play on this server.\\n\\n\"\n"
|
||||
"TLC_LINEBREAK_MINUS \"------------------\\n\"\n"
|
||||
"TL_CSPECIALPRINT \"^%c%s\"\n"
|
||||
"TL_INT_SPACE \"%i \"\n"
|
||||
;
|
||||
|
||||
//client may remap messages from the server to a regional bit of text.
|
||||
//server may remap progs messages
|
||||
|
||||
//basic language is english (cos that's what (my version of) Quake uses).
|
||||
//translate is english->lang
|
||||
//untranslate is lang->english for console commands.
|
||||
|
||||
|
||||
|
||||
cvar_t language = {"language", "uk"};
|
||||
char lastlang[9];
|
||||
|
||||
typedef struct trans_s {
|
||||
char *english;
|
||||
char *foreign;
|
||||
struct trans_s *next;
|
||||
} trans_t;
|
||||
|
||||
trans_t *firsttranslation;
|
||||
|
||||
void TranslateReset(void)
|
||||
{
|
||||
trans_t *trans;
|
||||
char *f, *eng, *fore;
|
||||
// FILE *F;
|
||||
char *s, *s1, *s2;
|
||||
/*
|
||||
if (*lastlang)
|
||||
{
|
||||
//write
|
||||
F = fopen(va("%s/%s.lng", com_gamedir, lastlang), "wb");
|
||||
if (F)
|
||||
{
|
||||
for (trans = firsttranslation; trans; trans=trans->next)
|
||||
{
|
||||
if (strchr(trans->english, '\n') || strchr(trans->english, '\"') || strchr(trans->english, '\\') || strchr(trans->english, '\t'))
|
||||
{
|
||||
s = trans->english;
|
||||
fputc('"', F);
|
||||
while(*s)
|
||||
{
|
||||
if (*s == '\n')
|
||||
fprintf(F, "\\n");
|
||||
else if (*s == '\\')
|
||||
fprintf(F, "\\\\");
|
||||
else if (*s == '\"')
|
||||
fprintf(F, "\"");
|
||||
else if (*s == '\t')
|
||||
fprintf(F, "\\t");
|
||||
else
|
||||
fputc(*s, F);
|
||||
|
||||
s++;
|
||||
}
|
||||
fputc('"', F);
|
||||
}
|
||||
else
|
||||
fprintf(F, "\"%s\"", trans->english);
|
||||
fputc(' ', F);
|
||||
if (strchr(trans->foreign, '\n') || strchr(trans->foreign, '\"') || strchr(trans->foreign, '\\') || strchr(trans->foreign, '\t'))
|
||||
{
|
||||
s = trans->foreign;
|
||||
fputc('"', F);
|
||||
while(*s)
|
||||
{
|
||||
if (*s == '\n')
|
||||
fprintf(F, "\\n");
|
||||
else if (*s == '\\')
|
||||
fprintf(F, "\\\\");
|
||||
else if (*s == '\"')
|
||||
fprintf(F, "\"");
|
||||
else if (*s == '\t')
|
||||
fprintf(F, "\\t");
|
||||
else
|
||||
fputc(*s, F);
|
||||
|
||||
s++;
|
||||
}
|
||||
fputc('"', F);
|
||||
fputc('\n', F);
|
||||
}
|
||||
else
|
||||
fprintf(F, "\"%s\"\n", trans->foreign);
|
||||
}
|
||||
fclose(F);
|
||||
}
|
||||
}*/
|
||||
Q_strncpyz(lastlang, language.string, 8);
|
||||
if (*language.string)
|
||||
{
|
||||
firsttranslation = NULL;
|
||||
//read in
|
||||
f = COM_LoadTempFile(va("%s.lng", lastlang));
|
||||
s = f;
|
||||
next:
|
||||
while (s && *s)
|
||||
{
|
||||
if (*s == '\"')
|
||||
{
|
||||
s++;
|
||||
eng = s;
|
||||
|
||||
while(*s)
|
||||
{
|
||||
if (*s == '\"')
|
||||
{
|
||||
*s = '\0'; //end of from
|
||||
s++;
|
||||
while (*s)
|
||||
{
|
||||
if (*s == '\"')
|
||||
{
|
||||
s++;
|
||||
fore = s;
|
||||
|
||||
while(*s)
|
||||
{
|
||||
if (*s == '\"')
|
||||
{
|
||||
*s = '\0'; //end of to
|
||||
s++;
|
||||
if (!firsttranslation)
|
||||
trans = firsttranslation = Z_Malloc(sizeof(trans_t)+strlen(eng)+strlen(fore)+2);
|
||||
else
|
||||
{
|
||||
for (trans = firsttranslation; trans->next; trans=trans->next) ;
|
||||
trans = (trans->next = Z_Malloc(sizeof(trans_t)+strlen(eng)+strlen(fore)+2));
|
||||
}
|
||||
|
||||
trans->english = (char *)(trans+1);
|
||||
trans->foreign = trans->english + strlen(eng) + 1;
|
||||
|
||||
s1 = trans->english;
|
||||
s2 = eng;
|
||||
while(*s2)
|
||||
{
|
||||
if (*s2 == '\\')
|
||||
{
|
||||
s2++;
|
||||
switch(*s2)
|
||||
{
|
||||
case 'n':
|
||||
*s1 = '\n';
|
||||
break;
|
||||
case '\"':
|
||||
*s1 = '\"';
|
||||
break;
|
||||
case 't':
|
||||
*s1 = '\t';
|
||||
break;
|
||||
case '\\':
|
||||
*s1 = '\\';
|
||||
break;
|
||||
default:
|
||||
*s1 = '?';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
*s1 = *s2;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
//strcpy(trans->english, eng);
|
||||
s1 = trans->foreign;
|
||||
s2 = fore;
|
||||
while(*s2)
|
||||
{
|
||||
if (*s2 == '\\')
|
||||
{
|
||||
s2++;
|
||||
switch(*s2)
|
||||
{
|
||||
case 'n':
|
||||
*s1 = '\n';
|
||||
break;
|
||||
case '\"':
|
||||
*s1 = '\"';
|
||||
break;
|
||||
case 't':
|
||||
*s1 = '\t';
|
||||
break;
|
||||
case '\\':
|
||||
*s1 = '\\';
|
||||
break;
|
||||
default:
|
||||
*s1 = '?';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
*s1 = *s2;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
// strcpy(trans->foreign, fore);
|
||||
goto next;
|
||||
}
|
||||
else if (*s == '\\') //skip
|
||||
s++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
else if (*s == '\\') //skip
|
||||
s++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
else if (*s == '\\') //skip
|
||||
s++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
else if (*s == '\\') //skip
|
||||
s++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *Translate(char *message)
|
||||
{
|
||||
trans_t *trans;
|
||||
if (!*message)
|
||||
return message;
|
||||
if (Q_strncmp(language.string, lastlang, 8))
|
||||
{
|
||||
TranslateReset();
|
||||
}
|
||||
|
||||
for (trans = firsttranslation; trans; trans=trans->next)
|
||||
{
|
||||
if (*trans->english == *message) //it's a little faster
|
||||
if (!Q_strcmp(trans->english+1, message+1))
|
||||
return trans->foreign;
|
||||
}
|
||||
|
||||
//add translation info to data
|
||||
|
||||
if (!firsttranslation)
|
||||
trans = firsttranslation = Z_Malloc(sizeof(trans_t) + strlen(message)+1);
|
||||
else
|
||||
{
|
||||
for (trans = firsttranslation; trans->next; trans=trans->next) ;
|
||||
trans = (trans->next = Z_Malloc(sizeof(trans_t) + strlen(message)+1));
|
||||
}
|
||||
trans->english = (char *)(trans+1);
|
||||
trans->foreign = (char *)(trans+1);
|
||||
strcpy(trans->english, message);
|
||||
//strcpy(trans->foreign, message);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
char *untranslate(char *message)
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
void TranslateInit(void)
|
||||
{
|
||||
Cvar_Register(&language, "International variables");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
char *languagetext[STL_MAXSTL][MAX_LANGUAGES];
|
||||
|
||||
void TL_ParseLanguage (char *name, char *data, int num) //this is one of the first functions to be called. so it mustn't use any quake subsystem routines
|
||||
{
|
||||
int i;
|
||||
char *s;
|
||||
|
||||
s = data;
|
||||
while(s)
|
||||
{
|
||||
s = COM_Parse(s);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
for (i = 0; i < STL_MAXSTL; i++)
|
||||
{
|
||||
if (!strcmp(com_token, langtext(i, 0))) //lang 0 is actually the string names.
|
||||
break;
|
||||
}
|
||||
|
||||
s = COM_ParseCString(s);
|
||||
if (i == STL_MAXSTL) //silently ignore - allow other servers or clients to add stuff
|
||||
continue;
|
||||
|
||||
langtext(i, num) = malloc(strlen(com_token)+1);
|
||||
strcpy(langtext(i, num), com_token);
|
||||
// langtext(i, num) = "";
|
||||
}
|
||||
}
|
||||
|
||||
void TL_LoadLanguage (char *name, char *shortname, int num) //this is one of the first functions to be called.
|
||||
{
|
||||
FILE *f;
|
||||
int size;
|
||||
char *buffer;
|
||||
|
||||
f = fopen(va("%s.trl", shortname), "rb");
|
||||
if (!f)
|
||||
return;
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
buffer = malloc(size+1);
|
||||
buffer[size] = '\0';
|
||||
fread(buffer, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
TL_ParseLanguage(name, buffer, num);
|
||||
free(buffer);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
#define CONVERTDEFAULT
|
||||
#endif
|
||||
#ifdef CONVERTDEFAULT
|
||||
|
||||
char *TL_ExpandToCString(char *in)
|
||||
{
|
||||
static char buffer[2048];
|
||||
char *out = buffer;
|
||||
|
||||
while(*in)
|
||||
{
|
||||
if (*in == '\"' || *in == '\\')
|
||||
{
|
||||
*out++ = '\\';
|
||||
*out = *in;
|
||||
}
|
||||
else if (*in == '\n')
|
||||
{
|
||||
*out++ = '\\';
|
||||
*out++ = 'n';
|
||||
*out++ = '\"';
|
||||
*out++ = '\n';
|
||||
*out = '\"';
|
||||
}
|
||||
/* else if (*in == '\t')
|
||||
{
|
||||
*out++ = '\\';
|
||||
*out = '\t';
|
||||
}*/
|
||||
else if (*in == '\r')
|
||||
{
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = *in;
|
||||
}
|
||||
|
||||
out++;
|
||||
in++;
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
char *TL_ExpandToDoubleCString(char *in) //TL_ExpandToCString twice
|
||||
{
|
||||
static char buffer[2048];
|
||||
char *out = buffer;
|
||||
|
||||
while(*in)
|
||||
{
|
||||
if (*in == '\"' || *in == '\\')
|
||||
{
|
||||
*out++ = '\\';
|
||||
*out = *in;
|
||||
}
|
||||
else if (*in == '\n')
|
||||
{
|
||||
*out++ = '\\';
|
||||
*out = 'n';
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = *in;
|
||||
}
|
||||
|
||||
out++;
|
||||
in++;
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return TL_ExpandToCString(buffer);
|
||||
}
|
||||
void TL_WriteTLHeader(void)
|
||||
{
|
||||
/*
|
||||
int i;
|
||||
FILE *f;
|
||||
f = fopen("tlout.h", "wb");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
for (i = 0; i < STL_MAXSTL; i++)
|
||||
{
|
||||
if (langtext(i, 1))
|
||||
{
|
||||
fprintf(f, "\"%s \\\"%s\\\"\\n\"\n", langtext(i, 0), TL_ExpandToDoubleCString(langtext(i, 1)));
|
||||
}
|
||||
}
|
||||
fclose(f);*/
|
||||
}
|
||||
#endif
|
||||
|
||||
void TL_InitLanguages(void)
|
||||
{
|
||||
int i, j;
|
||||
int lang;
|
||||
|
||||
#define NAME(i) (languagetext[i][0] = #i);
|
||||
#include "translate.h"
|
||||
#undef NAME
|
||||
/*
|
||||
#define ENGLISH(i, s) (languagetext[i][1] = s)
|
||||
#undef ENGLISH
|
||||
*/
|
||||
TL_ParseLanguage("English", defaultlanguagetext, 1);
|
||||
TL_LoadLanguage("English", "english", 1);
|
||||
TL_LoadLanguage("Spanish", "spanish", 2);
|
||||
TL_LoadLanguage("Portuguese", "portu", 3);
|
||||
TL_LoadLanguage("French", "french", 4);
|
||||
|
||||
if ((i = COM_CheckParm("-lang")))
|
||||
lang = atoi(com_argv[i+1]);
|
||||
else
|
||||
lang = 1;
|
||||
|
||||
if (lang < 1)
|
||||
lang = 1;
|
||||
if (lang >= MAX_LANGUAGES)
|
||||
lang = MAX_LANGUAGES-1;
|
||||
#ifndef CLIENTONLY
|
||||
svs.language = lang;
|
||||
#endif
|
||||
#ifndef SERVERONLY
|
||||
cls.language = lang;
|
||||
#endif
|
||||
|
||||
#ifdef CONVERTDEFAULT
|
||||
TL_WriteTLHeader();
|
||||
#endif
|
||||
|
||||
// Sys_Printf("-lang %i\n", lang);
|
||||
|
||||
for (i = 0; i < STL_MAXSTL; i++)
|
||||
{
|
||||
if (!langtext(i, 1))
|
||||
{
|
||||
Sys_Printf("warning: default translation for %s isn't set\n", langtext(i, 0));
|
||||
langtext(i, 1) = "";
|
||||
}
|
||||
}
|
||||
if (COM_CheckParm("-langugly")) //so non-translated strings show more clearly (and you know what they are called).
|
||||
{
|
||||
for (j = 2; j < MAX_LANGUAGES; j++)
|
||||
for (i = 0; i < STL_MAXSTL; i++)
|
||||
{
|
||||
if (!langtext(i, j))
|
||||
{
|
||||
langtext(i, j) = langtext(i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 2; j < MAX_LANGUAGES; j++)
|
||||
for (i = 0; i < STL_MAXSTL; i++)
|
||||
{
|
||||
if (!langtext(i, j))
|
||||
{
|
||||
langtext(i, j) = langtext(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//this stuff is for hexen2 translation strings.
|
||||
//(hexen2 is uuuuggllyyyy...)
|
||||
char *strings_list;
|
||||
char **strings_table;
|
||||
int strings_count;
|
||||
qboolean strings_loaded;
|
||||
void T_FreeStrings(void)
|
||||
{ //on map change, following gamedir change
|
||||
if (strings_loaded)
|
||||
{
|
||||
BZ_Free(strings_list);
|
||||
BZ_Free(strings_table);
|
||||
strings_count = 0;
|
||||
strings_loaded = false;
|
||||
}
|
||||
}
|
||||
void T_LoadString(void)
|
||||
{
|
||||
int i;
|
||||
char *s, *s2;
|
||||
//count new lines
|
||||
strings_loaded = true;
|
||||
strings_count = 0;
|
||||
strings_list = COM_LoadMallocFile("strings.txt");
|
||||
if (!strings_list)
|
||||
return;
|
||||
|
||||
for (s = strings_list; *s; s++)
|
||||
{
|
||||
if (*s == '\n')
|
||||
strings_count++;
|
||||
}
|
||||
strings_table = BZ_Malloc(sizeof(char*)*strings_count);
|
||||
|
||||
s = strings_list;
|
||||
for (i = 0; i < strings_count; i++)
|
||||
{
|
||||
strings_table[i] = s;
|
||||
s2 = strchr(s, '\n');
|
||||
if (!s2)
|
||||
break;
|
||||
|
||||
while (s < s2)
|
||||
{
|
||||
if (*s == '\r')
|
||||
*s = '\0';
|
||||
else if (*s == '^' || *s == '@') //becomes new line
|
||||
*s = '\n';
|
||||
s++;
|
||||
}
|
||||
s = s2+1;
|
||||
*s2 = '\0';
|
||||
}
|
||||
}
|
||||
char *T_GetString(int num)
|
||||
{
|
||||
if (!strings_loaded)
|
||||
{
|
||||
T_LoadString();
|
||||
}
|
||||
if (num<0 || num >= strings_count)
|
||||
return "BAD STRING";
|
||||
|
||||
return strings_table[num];
|
||||
}
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
#ifdef TRANSLATE_H
|
||||
NAME(STL_LANGUAGENAME)
|
||||
|
||||
NAME(TL_NL)
|
||||
NAME(TL_ST)
|
||||
NAME(TL_STNL)
|
||||
|
||||
NAME(STL_CLIENTCONNECTED)
|
||||
NAME(STL_SPECTATORCONNECTED)
|
||||
NAME(STL_RECORDEDCLIENTCONNECTED)
|
||||
NAME(STL_RECORDEDSPECTATORCONNECTED)
|
||||
NAME(STL_CLIENTWASBANNED)
|
||||
NAME(STL_YOUWEREBANNED)
|
||||
NAME(STL_YOUAREBANNED)
|
||||
NAME(STL_CLIENTTIMEDOUT)
|
||||
NAME(STL_LOADZOMIBETIMEDOUT)
|
||||
NAME(STL_CLIENTWASKICKED)
|
||||
NAME(STL_YOUWEREKICKED)
|
||||
NAME(STL_YOUWEREKICKEDNAMESPAM)
|
||||
NAME(STL_CLIENTKICKEDNAMESPAM)
|
||||
NAME(STL_GODON)
|
||||
NAME(STL_GODOFF)
|
||||
NAME(STL_NOCLIPON)
|
||||
NAME(STL_NOCLIPOFF)
|
||||
|
||||
NAME(STL_CLIENTISCUFFEDPERMANENTLY)
|
||||
NAME(STL_CLIENTISCUFFED)
|
||||
NAME(STL_CLIENTISSTILLCUFFED)
|
||||
NAME(STL_YOUWERECUFFED)
|
||||
NAME(STL_YOUARNTCUFFED)
|
||||
|
||||
NAME(STL_CLIENTISCRIPPLEDPERMANENTLY)
|
||||
NAME(STL_CLIENTISCRIPPLED)
|
||||
NAME(STL_CLIENTISSTILLCRIPPLED)
|
||||
NAME(STL_YOUWERECLIPPLED)
|
||||
NAME(STL_YOUARNTCRIPPLED)
|
||||
|
||||
NAME(STL_CLIENTISMUTEDPERMANENTLY)
|
||||
NAME(STL_CLIENTISMUTED)
|
||||
NAME(STL_CLIENTISSTILLMUTED)
|
||||
NAME(STL_YOUAREMUTED)
|
||||
NAME(STL_YOUARNTMUTED)
|
||||
NAME(STL_NONAMEASMUTE)
|
||||
NAME(STL_MUTEDVOTE)
|
||||
NAME(STL_MUTEDCHAT)
|
||||
NAME(STL_FLOODPROTACTIVE)
|
||||
NAME(STL_FLOODPROTTIME)
|
||||
|
||||
NAME(STL_BUFFERPROTECTION)
|
||||
|
||||
NAME(STL_FIRSTGREETING)
|
||||
NAME(STL_SHORTGREETING)
|
||||
NAME(STL_BIGGREETING)
|
||||
|
||||
NAME(STL_POSSIBLEMODELCHEAT)
|
||||
NAME(STL_MAPCHEAT)
|
||||
NAME(STL_INVALIDTRACKCLIENT)
|
||||
NAME(STL_BADNAME)
|
||||
NAME(STL_CLIENTNAMECHANGE)
|
||||
NAME(STL_SERVERPAUSED)
|
||||
NAME(STL_UPLOADDENIED)
|
||||
NAME(STL_NAMEDCLIENTDOESNTEXIST)
|
||||
NAME(STL_NOSUISIDEWHENDEAD)
|
||||
NAME(STL_CANTPAUSE)
|
||||
NAME(STL_CANTPAUSESPEC)
|
||||
NAME(STL_CLIENTPAUSED)
|
||||
NAME(STL_CLIENTUNPAUSED)
|
||||
NAME(STL_CLIENTLESSUNPAUSE)
|
||||
NAME(STL_CURRENTRATE)
|
||||
NAME(STL_RATESETTO)
|
||||
NAME(STL_CURRENTMSGLEVEL)
|
||||
NAME(STL_MSGLEVELSET)
|
||||
NAME(STL_GAMESAVED)
|
||||
|
||||
NAME(STL_CLIENTDROPPED)
|
||||
NAME(STL_SNAPREFUSED)
|
||||
NAME(STL_FINALVOTE)
|
||||
NAME(STL_VOTE)
|
||||
|
||||
NAME(STL_SPEEDCHEATKICKED)
|
||||
NAME(STL_SPEEDCHEATPOSSIBLE)
|
||||
|
||||
NAME(STL_INITED)
|
||||
NAME(STL_BACKBUFSET)
|
||||
NAME(STL_MESSAGEOVERFLOW)
|
||||
|
||||
|
||||
|
||||
NAME(STL_BUILDINGPHS)
|
||||
NAME(STL_PHSINFO)
|
||||
|
||||
NAME(STL_BREAKSTATEMENT)
|
||||
NAME(STL_BADSPRINT)
|
||||
NAME(STL_NOPRECACHE)
|
||||
NAME(STL_CANTFREEWORLD)
|
||||
NAME(STL_CANTFREEPLAYERS)
|
||||
NAME(STL_COMPILEROVER)
|
||||
NAME(STL_EDICTWASFREE)
|
||||
NAME(STL_NOFREEEDICTS)
|
||||
|
||||
NAME(STL_NEEDCHEATPARM)
|
||||
NAME(STL_USERDOESNTEXIST)
|
||||
|
||||
NAME(STL_MAPCOMMANDUSAGE)
|
||||
|
||||
NAME(STL_NOVOTING)
|
||||
NAME(STL_BADVOTE)
|
||||
NAME(STL_VOTESREMOVED)
|
||||
NAME(STL_OLDVOTEREMOVED)
|
||||
|
||||
|
||||
NAME(TL_EXECING)
|
||||
NAME(TL_EXECCOMMANDUSAGE)
|
||||
NAME(TL_EXECFAILED)
|
||||
NAME(TL_FUNCOVERFLOW)
|
||||
|
||||
NAME(TL_CURRENTALIASCOMMANDS)
|
||||
NAME(TL_ALIASNAMETOOLONG)
|
||||
NAME(TL_ALIASRESTRICTIONLEVELERROR)
|
||||
NAME(TL_ALIASLEVELCOMMANDUSAGE)
|
||||
NAME(TL_ALIASNOTFOUND)
|
||||
NAME(TL_ALIASRAISELEVELERROR)
|
||||
NAME(TL_ALIASRESTRICTIONLEVELWARN)
|
||||
NAME(TL_ALIASRESTRICTLEVEL)
|
||||
|
||||
NAME(TL_ALIASLIST)
|
||||
NAME(TL_COMMANDLISTHEADER)
|
||||
NAME(TL_CVARLISTHEADER)
|
||||
|
||||
NAME(TL_RESTRICTCOMMANDRAISE)
|
||||
NAME(TL_RESTRICTCOMMANDTOOHIGH)
|
||||
NAME(TL_RESTRICTCURRENTLEVEL)
|
||||
NAME(TL_RESTRICTCURRENTLEVELDEFAULT)
|
||||
NAME(TL_RESTRICTNOTDEFINED)
|
||||
NAME(TL_WASRESTIRCTED)
|
||||
NAME(TL_COMMANDNOTDEFINED)
|
||||
|
||||
NAME(TL_IFSYNTAX)
|
||||
NAME(TL_IFSYNTAXERROR)
|
||||
|
||||
NAME(TL_SETSYNTAX)
|
||||
|
||||
NAME(TL_CANTXNOTCONNECTED)
|
||||
|
||||
|
||||
|
||||
NAME(TL_SHAREWAREVERSION)
|
||||
NAME(TL_REGISTEREDVERSION)
|
||||
|
||||
NAME(TL_CURRENTSEARCHPATH)
|
||||
NAME(TL_SERACHPATHISPACK)
|
||||
NAME(TL_SERACHPATHISZIP)
|
||||
|
||||
NAME(TL_COMPRESSEDFILEOPENFAILED)
|
||||
NAME(TL_ADDEDPACKFILE)
|
||||
NAME(TL_COULDNTOPENZIP)
|
||||
|
||||
NAME(TL_ADDEDZIPFILE)
|
||||
NAME(TL_GAMEDIRAINTPATH)
|
||||
NAME(TL_KEYHASSLASH)
|
||||
NAME(TL_KEYHASQUOTE)
|
||||
NAME(TL_KEYTOOLONG)
|
||||
NAME(TL_INFOSTRINGTOOLONG)
|
||||
NAME(TL_STARKEYPROTECTED)
|
||||
NAME(TL_KEYHASNOVALUE)
|
||||
|
||||
|
||||
NAME(TL_OVERSIZEPACKETFROM)
|
||||
NAME(TL_CONNECTIONLOSTORABORTED)
|
||||
NAME(TL_NETGETPACKETERROR)
|
||||
NAME(TL_NETSENDERROR)
|
||||
NAME(TL_NETBINDINTERFACE)
|
||||
NAME(TL_IPADDRESSIS)
|
||||
NAME(TL_UDPINITED)
|
||||
NAME(TL_SERVERPORTINITED)
|
||||
NAME(TL_CLIENTPORTINITED)
|
||||
|
||||
NAME(TL_OUTMESSAGEOVERFLOW)
|
||||
NAME(TL_OUTOFORDERPACKET)
|
||||
NAME(TL_DROPPEDPACKETCOUNT)
|
||||
|
||||
NAME(STL_SERVERUNSPAWNED)
|
||||
NAME(STL_SERVERSPAWNED)
|
||||
|
||||
NAME(TL_EXEDATETIME)
|
||||
NAME(TL_HEAPSIZE)
|
||||
#ifdef VERSION3PART
|
||||
NAME(TL_VERSION3)
|
||||
NAME(TL_SERVERVERSION3)
|
||||
#else
|
||||
NAME(TL_VERSION2)
|
||||
NAME(TL_SERVERVERSION2)
|
||||
#endif
|
||||
|
||||
//savegame.c
|
||||
NAME(STL_SAVESYNTAX)
|
||||
NAME(STL_NORELATIVEPATHS)
|
||||
NAME(STL_SAVEGAMETO)
|
||||
NAME(STL_ERRORCOULDNTOPEN)
|
||||
NAME(STL_SAVEDONE)
|
||||
NAME(STL_LOADSYNTAX)
|
||||
NAME(STL_LOADGAMEFROM)
|
||||
NAME(STL_BADSAVEVERSION)
|
||||
NAME(STL_LOADFAILED)
|
||||
|
||||
//sv_ccmds.c
|
||||
NAME(STL_NOMASTERMODE)
|
||||
NAME(STL_MASTERAT)
|
||||
NAME(STL_SENDINGPING)
|
||||
NAME(STL_SHUTTINGDOWN)
|
||||
NAME(STL_LOGGINGOFF)
|
||||
NAME(STL_LOGGINGTO)
|
||||
NAME(STL_FLOGGINGOFF)
|
||||
NAME(STL_FLOGGINGFAILED)
|
||||
NAME(STL_FLOGGINGTO)
|
||||
NAME(STL_USERIDNOTONSERVER)
|
||||
NAME(STL_CANTFINDMAP)
|
||||
NAME(STL_SERVERINFOSETTINGS)
|
||||
NAME(STL_SERVERINFOSYNTAX)
|
||||
NAME(STL_LOCALINFOSETTINGS)
|
||||
NAME(STL_LOCALINFOSYNTAX)
|
||||
NAME(STL_USERINFOSYNTAX)
|
||||
NAME(STL_FLOODPROTSETTINGS)
|
||||
NAME(STL_FLOODPROTNOTON)
|
||||
NAME(STL_FLOODPROTSYNTAX)
|
||||
NAME(STL_NONEGATIVEVALUES)
|
||||
NAME(STL_TRACK10PLUSSMESSAGES)
|
||||
NAME(STL_FLOODPROTCURRENTMESSAGE)
|
||||
NAME(STL_FLOODPROTMESSAGESYNTAX)
|
||||
NAME(STL_CURRENTGAMEDIR)
|
||||
NAME(STL_SVGAMEDIRUSAGE)
|
||||
NAME(STL_GAMEDIRCANTBEPATH)
|
||||
NAME(STL_GAMEDIRUSAGE)
|
||||
NAME(STL_SNAPTOOMANYFILES)
|
||||
NAME(STL_SNAPREQUEST)
|
||||
NAME(STL_SNAPUSAGE)
|
||||
|
||||
|
||||
NAME(TLC_VERSIONST3)
|
||||
NAME(TLC_VERSIONST2)
|
||||
NAME(TLC_VERSION2)
|
||||
NAME(TLC_BADSERVERADDRESS)
|
||||
NAME(TLC_ILLEGALSERVERADDRESS)
|
||||
NAME(TLC_CONNECTINGTO)
|
||||
NAME(TLC_SYNTAX_CONNECT)
|
||||
NAME(TLC_NORCONPASSWORD)
|
||||
NAME(TLC_NORCONDEST)
|
||||
NAME(TLC_SYNTAX_USER)
|
||||
NAME(TLC_USER_NOUSER)
|
||||
NAME(TLC_USERBANNER)
|
||||
NAME(TLC_USERBANNER2)
|
||||
NAME(TLC_USERLINE)
|
||||
NAME(TLC_USERTOTAL)
|
||||
NAME(TLC_COLOURCURRENT)
|
||||
NAME(TLC_SYNTAX_COLOUR)
|
||||
NAME(TLC_SYNTAX_FULLSERVERINFO)
|
||||
NAME(TLC_SERVER_VERSION)
|
||||
NAME(TLC_SYNTAX_FULLINFO)
|
||||
NAME(TLC_SYNTAX_SETINFO)
|
||||
NAME(TLC_PACKET_SYNTAX)
|
||||
NAME(TLC_BADADDRESS)
|
||||
NAME(TLC_CHANGINGMAP)
|
||||
NAME(TLC_RECONNECTING)
|
||||
NAME(TLC_RECONNECT_NOSERVER)
|
||||
NAME(TL_ST_COLON)
|
||||
NAME(TLC_GOTCONNECTION)
|
||||
NAME(TLC_DUPCONNECTION)
|
||||
NAME(TLC_CONNECTED)
|
||||
NAME(TLC_CONLESS_CONCMD)
|
||||
NAME(TLC_CMDFROMREMOTE)
|
||||
NAME(TL_LINEBREAK_EQUALS)
|
||||
NAME(TLC_LOCALID_NOTSET)
|
||||
NAME(TLC_LOCALID_BAD)
|
||||
NAME(TLC_A2C_PRINT)
|
||||
NAME(TLC_A2A_PING)
|
||||
NAME(TLC_S2C_CHALLENGE)
|
||||
NAME(TLC_CONLESSPACKET_UNKNOWN)
|
||||
NAME(TL_RUNTPACKET)
|
||||
NAME(TLC_SERVERTIMEOUT)
|
||||
NAME(TLC_CONNECTFIRST)
|
||||
NAME(TLC_SYNTAX_DOWNLOAD)
|
||||
NAME(TLC_REQUIRESSERVERMOD)
|
||||
NAME(TLC_CLIENTCON_ERROR_ENDGAME)
|
||||
NAME(TLC_HOSTFATALERROR)
|
||||
NAME(TLC_CONFIGCFG_WRITEFAILED)
|
||||
NAME(TLC_HOSTSPEEDSOUTPUT)
|
||||
NAME(TLC_QUAKEWORLD_INITED)
|
||||
NAME(TLC_DEDICATEDCANNOTCONNECT)
|
||||
NAME(TLC_Q2CONLESSPACKET_UNKNOWN)
|
||||
|
||||
NAME(TL_NORELATIVEPATHS)
|
||||
NAME(TL_NODOWNLOADINDEMO)
|
||||
NAME(TL_DOWNLOADINGFILE)
|
||||
NAME(TLC_CHECKINGMODELS)
|
||||
NAME(TLC_CHECKINGSOUNDS)
|
||||
NAME(TL_FILENOTFOUND)
|
||||
NAME(TL_CLS_DOWNLOAD_ISSET)
|
||||
NAME(TL_FAILEDTOOPEN)
|
||||
NAME(TL_RENAMEFAILED)
|
||||
NAME(TL_UPLOADCOMPLEATE)
|
||||
NAME(TL_FTEEXTENSIONS)
|
||||
NAME(TLC_LINEBREAK_NEWLEVEL)
|
||||
NAME(TLC_PC_PS_NL)
|
||||
NAME(TLC_NOQ2CINEMATICSSUPPORT)
|
||||
NAME(TLC_GOTSVDATAPACKET)
|
||||
NAME(TLC_BAD_MAXCLIENTS)
|
||||
NAME(TLC_TOOMANYMODELPRECACHES)
|
||||
NAME(TLC_TOOMANYSOUNDPRECACHES)
|
||||
NAME(TLC_PARSESTATICWITHNOMAP)
|
||||
NAME(TL_FILE_X_MISSING)
|
||||
NAME(TL_GETACLIENTPACK)
|
||||
NAME(TLC_LINEBREAK_MINUS)
|
||||
NAME(TL_CSPECIALPRINT)
|
||||
NAME(TL_INT_SPACE)
|
||||
|
||||
#else
|
||||
|
||||
#define TRANSLATE_H
|
||||
|
||||
typedef enum {
|
||||
#define NAME(s) s,
|
||||
#include "translate.h"
|
||||
#undef NAME
|
||||
STL_MAXSTL
|
||||
} translation_t;
|
||||
|
||||
#define MAX_LANGUAGES 64
|
||||
|
||||
void TranslateInit(void);
|
||||
|
||||
extern char *languagetext[STL_MAXSTL][MAX_LANGUAGES];
|
||||
|
||||
void SV_InitLanguages(void);
|
||||
|
||||
#define langtext(t,l) languagetext[t][l]
|
||||
|
||||
#ifdef VERSION3PART
|
||||
#define TL_VERSION TL_VERSION3
|
||||
#define TL_SERVERVERSION TL_SERVERVERSION3
|
||||
#else
|
||||
#define TL_VERSION TL_VERSION2
|
||||
#define TL_SERVERVERSION TL_SERVERVERSION2
|
||||
#endif
|
||||
|
||||
#define LANGDEFAULT 1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,174 @@
|
|||
//these structures are shared with the exe.
|
||||
|
||||
#define UIMAX_SCOREBOARDNAME 16
|
||||
#define UIMAX_INFO_STRING 196
|
||||
|
||||
#ifdef MAX_SCOREBOARDNAME
|
||||
#if MAX_SCOREBOARDNAME != UIMAX_SCOREBOARDNAME
|
||||
#pragma message("MAX_SCOREBOARDNAME doesn't match UIMAX_SCOREBOARDNAME")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef UIMAX_INFO_STRING
|
||||
#if UIMAX_INFO_STRING != UIMAX_INFO_STRING
|
||||
#pragma message("MAX_SCOREBOARDNAME doesn't match UIMAX_SCOREBOARDNAME")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int userid;
|
||||
char name[UIMAX_SCOREBOARDNAME]; //for faster reading.
|
||||
float starttime;
|
||||
int frags;
|
||||
int ping;
|
||||
int pl;
|
||||
|
||||
int topcolour;
|
||||
int bottomcolour;
|
||||
|
||||
char userinfo[UIMAX_INFO_STRING]; //should this size be enforced?
|
||||
//you can get all sorts of stuff like names.
|
||||
} vmuiclientinfo_t;
|
||||
|
||||
//useful for it's width/height. The others are a little pointless to be honest.
|
||||
typedef struct {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int bpp;
|
||||
unsigned int refreshrate; //quakeworld normally only draws 30 frames per second dontcha know?
|
||||
qboolean fullscreen; //oposite of windowed.
|
||||
char renderername[256]; //Human readable
|
||||
|
||||
int vidbugs; //flags for the buggy implementations of opengl or whatever.
|
||||
} vidinfo_t;
|
||||
|
||||
//is there any point to these?
|
||||
enum {
|
||||
VB_NOSCALE = 1<<0, //software rendering, incapable of scaling.
|
||||
VB_NOCOLOUR = 1<<1, //software rendering that doesn't allow belnding colours. (8 bit paletted)
|
||||
VB_NOCOLOURINTERP = 1<<2, //software rendering that supports a blending of colours, but not per vertex.
|
||||
|
||||
VB_NOINTERPOLATEALPHA = 1<<3, //riva128
|
||||
VB_NOMODULATEALPHA = 1<<4, //ragepro
|
||||
VB_NOSRCTIMESDST = 1<<5, //permedia
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SID_Q2STATUSBAR = -4,
|
||||
SID_Q2LAYOUT = -3,
|
||||
SID_CENTERPRINTTEXT = -2,
|
||||
SID_SERVERNAME = -1,
|
||||
//q2's config strings come here.
|
||||
} stringid_e;
|
||||
|
||||
#define UI_API_VERSION 5000
|
||||
typedef enum {
|
||||
UI_GETAPIVERSION = 0,
|
||||
UI_INIT = 1,
|
||||
UI_SHUTDOWN = 2,
|
||||
UI_KEY_EVENT = 3,
|
||||
UI_MOUSE_DELTA = 4,
|
||||
UI_DRAWMENU = 5,
|
||||
UI_FULLSCREEN = 6,
|
||||
//return value expected
|
||||
//0 means don't take input
|
||||
//1 means engine should skip map/scrback update,
|
||||
//2 means fade the screen or draw console back. (expected to be most used)
|
||||
//3 means don't fade the screen
|
||||
|
||||
UI_DRAWSTATUSBAR = 500,
|
||||
UI_MOUSE_POS,
|
||||
UI_INTERMISSION,
|
||||
UI_FINALE,
|
||||
UI_STRINGCHANGED, //parma is the string id
|
||||
UI_NEWSERVER //indicates that all the strings have changed.
|
||||
} uiExport_t;
|
||||
|
||||
typedef enum {
|
||||
UI_SYSERROR = 0,
|
||||
UI_PRINT = 1,
|
||||
UI_CVAR_SET = 3,
|
||||
UI_CVAR_GET_VALUE = 4,
|
||||
UI_CVAR_GET_STRING = 5,
|
||||
UI_CVAR_SET_VALUE = 6,
|
||||
UI_CVAR_RESET = 7, //not yet implemented
|
||||
|
||||
UI_CBUF_ADD_COMMAND = 12,
|
||||
UI_FS_OPEN = 13,
|
||||
UI_FS_READ = 14,
|
||||
UI_FS_WRITE = 15,
|
||||
UI_FS_CLOSE = 16,
|
||||
UI_FS_LISTFILES = 17,
|
||||
|
||||
UI_PRECACHE_MODEL = 18,
|
||||
UI_PRECACHE_SKIN = 19, //fte doesn't implement.
|
||||
UI_DRAW_CACHEPIC = 20,
|
||||
|
||||
UI_SCENE_CLEAR = 21,
|
||||
UI_SCENE_ADD_ENTITY = 22,
|
||||
UI_SCENE_ADD_LIGHT = 24, //non-functional
|
||||
UI_SCENE_RENDER = 25,
|
||||
|
||||
UI_DRAW_COLOUR = 26,
|
||||
UI_DRAW_IMAGE = 27,
|
||||
UI_LERP_TAG = 29, //currently non-functional.
|
||||
|
||||
UI_SOUND_PRECACHE = 31,
|
||||
UI_SOUND_PLAY = 32,
|
||||
|
||||
UI_KEY_NAME = 33, //retrieves text for the name of a key - eg leftarrow
|
||||
UI_KEY_GETBINDING = 34,
|
||||
UI_KEY_SETBINDING = 35,
|
||||
UI_KEY_ISDOWN = 36,
|
||||
|
||||
UI_KEY_CLEARALL = 39,
|
||||
UI_KEY_GETDEST = 40,
|
||||
UI_KEY_SETDEST = 41,
|
||||
UI_GET_VID_CONFIG = 43, //very minimal
|
||||
UI_GET_CLIENT_STATE = 44, //not going to do anything btw.
|
||||
UI_GET_SERVERINFO = 45,
|
||||
|
||||
//server browser stuph.
|
||||
UI_MS_GETSERVERCOUNT = 46,
|
||||
UI_CLEAR_PINGS = 47,
|
||||
UI_GET_PINGADDRESS = 48,
|
||||
UI_GET_PINGINFO = 49,
|
||||
|
||||
UI_CVAR_REGISTER = 50,
|
||||
UI_CVAR_UPDATE = 51,
|
||||
UI_MEM_AVAILABLE = 52,
|
||||
|
||||
UI_CDKEY_GET = 53,
|
||||
UI_CDKEY_SET = 54,
|
||||
|
||||
UI_REGISTERFRONT = 55,
|
||||
|
||||
UI_GET_REALTIME = 62,
|
||||
UI_LAN_GET_COUNT = 65,
|
||||
UI_LAN_GET_ADDRESS = 66,
|
||||
|
||||
UI_SOMETHINGTHATRETURNSTRUE = 81,
|
||||
UI_SOMETHINGTODOWITHPUNKBUSTER = 87,
|
||||
|
||||
|
||||
|
||||
UI_MEMSET = 100,
|
||||
UI_MEMMOVE = 101,
|
||||
UI_STRNCPY = 102,
|
||||
UI_SIN = 103,
|
||||
UI_COS = 104,
|
||||
UI_ATAN2 = 105,
|
||||
UI_SQRT = 106,
|
||||
UI_FLOOR = 107,
|
||||
UI_CEIL = 108,
|
||||
|
||||
|
||||
|
||||
UI_CACHE_PIC = 500,
|
||||
UI_PICFROMWAD = 501,
|
||||
UI_GETPLAYERINFO = 502,
|
||||
UI_GETSTAT = 503,
|
||||
UI_GETVIDINFO = 504,
|
||||
UI_GET_STRING = 510,
|
||||
|
||||
} ui_builtinnum_t;
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef _VM_H
|
||||
#define _VM_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EXPORT_FN __cdecl
|
||||
#else
|
||||
#define EXPORT_FN
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
typedef int (EXPORT_FN *sys_call_t) (int arg, ...);
|
||||
typedef long (*sys_callex_t) (void *offset, unsigned int mask, int fn, const long *arg);
|
||||
|
||||
typedef struct vm_s vm_t;
|
||||
|
||||
// for syscall users
|
||||
#define VM_LONG(x) (*(long*)&(x))
|
||||
#define VM_FLOAT(x) (*(float*)&(x))
|
||||
#define VM_POINTER(x) ((x)?(void*)((char *)offset+((x)%mask)):NULL)
|
||||
// ------------------------- * interface * -------------------------
|
||||
|
||||
void VM_PrintInfo(vm_t *vm);
|
||||
vm_t *VM_Create(vm_t *vm, const char *name, sys_call_t syscall, sys_callex_t syscallex);
|
||||
void VM_Destroy(vm_t *vm);
|
||||
qboolean VM_Restart(vm_t *vm);
|
||||
int VARGS VM_Call(vm_t *vm, int instruction, ...);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//these things are specific to FTE QuakeWorld
|
||||
void UI_Init (void);
|
||||
void UI_Stop (void);
|
||||
qboolean UI_Q2LayoutChanged(void);
|
||||
void UI_StringChanged(int num);
|
||||
void UI_MousePosition(int xpos, int ypos);
|
||||
int UI_MenuState(void);
|
||||
qboolean UI_KeyPress(int key, qboolean down);
|
||||
void UI_Reset(void);
|
||||
void UI_DrawMenu(void);
|
||||
qboolean UI_DrawStatusBar(int scores);
|
||||
qboolean UI_DrawIntermission(void);
|
||||
qboolean UI_DrawFinale(void);
|
||||
int UI_MenuState(void);
|
||||
|
||||
#ifdef VM_CG
|
||||
void CG_Stop (void);
|
||||
void CG_Start (void);
|
||||
int CG_Refresh(void);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// world.h
|
||||
|
||||
typedef struct plane_s
|
||||
{
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
} plane_t;
|
||||
|
||||
typedef struct csurface_s
|
||||
{
|
||||
char name[16];
|
||||
int flags;
|
||||
int value;
|
||||
} q2csurface_t;
|
||||
|
||||
typedef struct cplane_s
|
||||
{
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
qbyte type; // for fast side tests
|
||||
qbyte signbits; // signx + (signy<<1) + (signz<<1)
|
||||
qbyte pad[2];
|
||||
} cplane_t;
|
||||
|
||||
/*
|
||||
typedef struct trace_s
|
||||
{
|
||||
qboolean allsolid; // if true, plane is not valid
|
||||
qboolean startsolid; // if true, the initial point was in a solid area
|
||||
qboolean inopen, inwater;
|
||||
float fraction; // time completed, 1.0 = didn't hit anything
|
||||
vec3_t endpos; // final position
|
||||
plane_t plane; // surface normal at impact
|
||||
edict_t *ent; // entity the surface is on
|
||||
} trace_t;
|
||||
*/
|
||||
|
||||
//these two structures must match (except for extra qw members)
|
||||
typedef struct trace_s
|
||||
{
|
||||
//DON'T ADD ANYTHING BETWEEN THIS LINE
|
||||
//q2 game dll code will memcpy the lot from trace_t to q2trace_t.
|
||||
qboolean allsolid; // if true, plane is not valid
|
||||
qboolean startsolid; // if true, the initial point was in a solid area
|
||||
float fraction; // time completed, 1.0 = didn't hit anything
|
||||
vec3_t endpos; // final position
|
||||
cplane_t plane; // surface normal at impact
|
||||
q2csurface_t *surface; // surface hit
|
||||
int contents; // contents on other side of surface hit
|
||||
struct edict_s *ent; // not set by CM_*() functions
|
||||
//AND THIS LINE
|
||||
int entnum;
|
||||
|
||||
qboolean inopen, inwater;
|
||||
} trace_t;
|
||||
|
||||
typedef struct q2trace_s
|
||||
{
|
||||
qboolean allsolid; // if true, plane is not valid
|
||||
qboolean startsolid; // if true, the initial point was in a solid area
|
||||
float fraction; // time completed, 1.0 = didn't hit anything
|
||||
vec3_t endpos; // final position
|
||||
cplane_t plane; // surface normal at impact
|
||||
q2csurface_t *surface; // surface hit
|
||||
int contents; // contents on other side of surface hit
|
||||
struct edict_s *ent; // not set by CM_*() functions
|
||||
} q2trace_t;
|
||||
|
||||
|
||||
#define MOVE_NORMAL 0
|
||||
#define MOVE_NOMONSTERS 1
|
||||
#define MOVE_MISSILE 2
|
||||
#define MOVE_HITMODEL 4
|
||||
|
||||
typedef struct areanode_s
|
||||
{
|
||||
int axis; // -1 = leaf node
|
||||
float dist;
|
||||
struct areanode_s *children[2];
|
||||
link_t trigger_edicts;
|
||||
link_t solid_edicts;
|
||||
} areanode_t;
|
||||
|
||||
#define AREA_DEPTH 4
|
||||
#define AREA_NODES 32 //pow(2, AREA_DEPTH+1)
|
||||
|
||||
extern areanode_t sv_areanodes[AREA_NODES];
|
||||
|
||||
|
||||
void SV_ClearWorld (void);
|
||||
// called after the world model has been loaded, before linking any entities
|
||||
|
||||
void SV_UnlinkEdict (edict_t *ent);
|
||||
// call before removing an entity, and before trying to move one,
|
||||
// so it doesn't clip against itself
|
||||
// flags ent->v.modified
|
||||
|
||||
void SV_LinkEdict (edict_t *ent, qboolean touch_triggers);
|
||||
// Needs to be called any time an entity changes origin, mins, maxs, or solid
|
||||
// flags ent->v.modified
|
||||
// sets ent->v.absmin and ent->v.absmax
|
||||
// if touchtriggers, calls prog functions for the intersected triggers
|
||||
|
||||
int SV_PointContents (vec3_t p);
|
||||
// returns the CONTENTS_* value from the world at the given point.
|
||||
// does not check any entities at all
|
||||
|
||||
edict_t *SV_TestEntityPosition (edict_t *ent);
|
||||
|
||||
trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict);
|
||||
// mins and maxs are reletive
|
||||
|
||||
// if the entire move stays in a solid volume, trace.allsolid will be set
|
||||
|
||||
// if the starting point is in a solid, it will be allowed to move out
|
||||
// to an open area
|
||||
|
||||
// nomonsters is used for line of sight or edge testing, where mosnters
|
||||
// shouldn't be considered solid objects
|
||||
|
||||
// passedict is explicitly excluded from clipping checks (normally NULL)
|
||||
|
||||
|
||||
edict_t *SV_TestPlayerPosition (edict_t *ent, vec3_t origin);
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// draw.h -- these are the only functions outside the refresh allowed
|
||||
// to touch the vid buffer
|
||||
|
||||
void GLDraw_Init (void);
|
||||
void GLDraw_ReInit (void);
|
||||
void GLDraw_DeInit (void);
|
||||
void GLSurf_DeInit (void);
|
||||
void GLDraw_Character (int x, int y, unsigned int num);
|
||||
void GLDraw_ColouredCharacter (int x, int y, unsigned int num);
|
||||
void GLDraw_DebugChar (qbyte num);
|
||||
void GLDraw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height);
|
||||
void GLDraw_Pic (int x, int y, qpic_t *pic);
|
||||
void GLDraw_TransPic (int x, int y, qpic_t *pic);
|
||||
void GLDraw_TransPicTranslate (int x, int y, qpic_t *pic, qbyte *translation);
|
||||
void GLDraw_ConsoleBackground (int lines);
|
||||
void GLDraw_EditorBackground (int lines);
|
||||
void GLDraw_BeginDisc (void);
|
||||
void GLDraw_EndDisc (void);
|
||||
void GLDraw_TileClear (int x, int y, int w, int h);
|
||||
void GLDraw_Fill (int x, int y, int w, int h, int c);
|
||||
void GLDraw_FadeScreen (void);
|
||||
void GLDraw_String (int x, int y, const qbyte *str);
|
||||
void GLDraw_Alt_String (int x, int y, const qbyte *str);
|
||||
qpic_t *GLDraw_SafePicFromWad (char *name);
|
||||
qpic_t *GLDraw_PicFromWad (char *name);
|
||||
qpic_t *GLDraw_SafeCachePic (char *path);
|
||||
qpic_t *GLDraw_CachePic (char *path);
|
||||
void GLDraw_Crosshair(void);
|
||||
void GLDraw_LevelPic (qpic_t *pic);
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
#define SHADER_PASS_MAX 8
|
||||
#define SHADER_MAX_TC_MODS 8
|
||||
#define SHADER_DEFORM_MAX 8
|
||||
#define SHADER_MAX_ANIMFRAMES 8
|
||||
|
||||
//colour manipulation
|
||||
typedef struct
|
||||
{
|
||||
enum {
|
||||
SHADER_FUNC_SIN,
|
||||
SHADER_FUNC_TRIANGLE,
|
||||
SHADER_FUNC_SQUARE,
|
||||
SHADER_FUNC_SAWTOOTH,
|
||||
SHADER_FUNC_INVERSESAWTOOTH,
|
||||
SHADER_FUNC_NOISE
|
||||
} type; // SHADER_FUNC enum
|
||||
float args[4]; // offset, amplitude, phase_offset, rate
|
||||
} shaderfunc_t;
|
||||
|
||||
//tecture coordinate manipulation
|
||||
typedef struct
|
||||
{
|
||||
enum {
|
||||
SHADER_TCMOD_NONE, //bug
|
||||
SHADER_TCMOD_SCALE, //some sorta tabled deformation
|
||||
SHADER_TCMOD_SCROLL, //boring moving texcoords with time
|
||||
SHADER_TCMOD_STRETCH, //constant factor
|
||||
SHADER_TCMOD_ROTATE
|
||||
} type;
|
||||
float args[6];
|
||||
} tcmod_t;
|
||||
|
||||
//vertex positioning manipulation.
|
||||
typedef struct
|
||||
{
|
||||
enum {
|
||||
DEFORMV_NONE, //bug
|
||||
DEFORMV_MOVE,
|
||||
DEFORMV_WAVE,
|
||||
DEFORMV_NORMAL,
|
||||
DEFORMV_BULGE,
|
||||
DEFORMV_AUTOSPRITE,
|
||||
DEFORMV_AUTOSPRITE2,
|
||||
DEFORMV_PROJECTION_SHADOW
|
||||
} type;
|
||||
float args[4];
|
||||
shaderfunc_t func;
|
||||
} deformv_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int mergedpasses;
|
||||
|
||||
shaderfunc_t rgbgen_func;
|
||||
shaderfunc_t alphagen_func;
|
||||
|
||||
|
||||
unsigned int blendsrc, blenddst; // glBlendFunc args
|
||||
unsigned int blendmode, envmode;
|
||||
|
||||
unsigned int combinesrc0, combinesrc1, combinemode;
|
||||
|
||||
unsigned int depthfunc; // glDepthFunc arg
|
||||
enum {
|
||||
SHADER_ALPHA_GT0,
|
||||
SHADER_ALPHA_LT128,
|
||||
SHADER_ALPHA_GE128
|
||||
} alphafunc;
|
||||
|
||||
enum {
|
||||
TC_GEN_BASE, //basic specified texture coords
|
||||
TC_GEN_LIGHTMAP, //use loaded lightmap coords
|
||||
TC_GEN_ENVIRONMENT,
|
||||
TC_GEN_DOTPRODUCT
|
||||
} tcgen;
|
||||
enum {
|
||||
RGB_GEN_WAVE,
|
||||
RGB_GEN_ENTITY,
|
||||
RGB_GEN_ONE_MINUS_ENTITY,
|
||||
RGB_GEN_VERTEX,
|
||||
RGB_GEN_EXACT_VERTEX,
|
||||
RGB_GEN_ONE_MINUS_VERTEX,
|
||||
RGB_GEN_IDENTITY_LIGHTING,
|
||||
RGB_GEN_IDENTITY,
|
||||
RGB_GEN_CONST
|
||||
} rgbgen;
|
||||
enum {
|
||||
ALPHA_GEN_ENTITY,
|
||||
ALPHA_GEN_WAVE,
|
||||
ALPHA_GEN_PORTAL,
|
||||
ALPHA_GEN_SPECULAR,
|
||||
ALPHA_GEN_IDENTITY
|
||||
} alphagen;
|
||||
|
||||
int numtcmods;
|
||||
tcmod_t tcmod[SHADER_MAX_TC_MODS];
|
||||
|
||||
int anim_numframes;
|
||||
int anim_frames[SHADER_MAX_ANIMFRAMES];
|
||||
float fps;
|
||||
unsigned int texturetype;
|
||||
|
||||
enum {
|
||||
SHADER_PASS_BLEND = 1 << 0,
|
||||
SHADER_PASS_ALPHAFUNC = 1 << 1,
|
||||
SHADER_PASS_DEPTHWRITE = 1 << 2
|
||||
} flags;
|
||||
} shaderpass_t;
|
||||
|
||||
typedef struct shader_s {
|
||||
int numpasses; //careful... 0 means it's not loaded... and not actually a proper shader.
|
||||
struct shader_s *next;
|
||||
char name[MAX_QPATH];
|
||||
//end of shared fields.
|
||||
|
||||
byte_vec4_t fog_color;
|
||||
|
||||
int numdeforms;
|
||||
deformv_t deforms[SHADER_DEFORM_MAX];
|
||||
|
||||
enum {
|
||||
SHADER_SKY = 1 << 0,
|
||||
SHADER_NOMIPMAPS = 1 << 1,
|
||||
SHADER_NOPICMIP = 1 << 2,
|
||||
SHADER_CULL_FRONT = 1 << 3,
|
||||
SHADER_CULL_BACK = 1 << 4,
|
||||
SHADER_DEFORMV_BULGE = 1 << 5,
|
||||
SHADER_AUTOSPRITE = 1 << 5
|
||||
} flags;
|
||||
|
||||
shaderpass_t pass[SHADER_PASS_MAX];
|
||||
} shader_t;
|
||||
|
||||
|
||||
|
||||
|
||||
void GLR_MeshInit(void);
|
||||
void GL_DrawMesh(mesh_t *mesh, shader_t *shader, int texturenum, int lmtexturenum);
|
||||
void GL_DrawMeshBump(mesh_t *mesh, int texturenum, int lmtexturenum, int bumpnum, int deluxnum);
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
/* file generated by qcc, do not modify */
|
||||
|
||||
typedef struct globalvars_s /*
|
||||
{ int pad[28];
|
||||
int self;
|
||||
int other;
|
||||
int world;
|
||||
float time;
|
||||
float frametime;
|
||||
int newmis;
|
||||
float force_retouch;
|
||||
string_t mapname;
|
||||
float serverflags;
|
||||
float total_secrets;
|
||||
float total_monsters;
|
||||
float found_secrets;
|
||||
float killed_monsters;
|
||||
float parm1;
|
||||
float parm2;
|
||||
float parm3;
|
||||
float parm4;
|
||||
float parm5;
|
||||
float parm6;
|
||||
float parm7;
|
||||
float parm8;
|
||||
float parm9;
|
||||
float parm10;
|
||||
float parm11;
|
||||
float parm12;
|
||||
float parm13;
|
||||
float parm14;
|
||||
float parm15;
|
||||
float parm16;
|
||||
vec3_t v_forward;
|
||||
vec3_t v_up;
|
||||
vec3_t v_right;
|
||||
float trace_allsolid;
|
||||
float trace_startsolid;
|
||||
float trace_fraction;
|
||||
vec3_t trace_endpos;
|
||||
vec3_t trace_plane_normal;
|
||||
float trace_plane_dist;
|
||||
int trace_ent;
|
||||
float trace_inopen;
|
||||
float trace_inwater;
|
||||
int msg_entity;
|
||||
func_t main;
|
||||
func_t StartFrame;
|
||||
func_t PlayerPreThink;
|
||||
func_t PlayerPostThink;
|
||||
func_t ClientKill;
|
||||
func_t ClientConnect;
|
||||
func_t PutClientInServer;
|
||||
func_t ClientDisconnect;
|
||||
func_t SetNewParms;
|
||||
func_t SetChangeParms;
|
||||
}*/ globalvars_t;
|
||||
|
||||
typedef struct nqglobalvars_s
|
||||
{ int *pad[28];
|
||||
int *self;
|
||||
int *other;
|
||||
int *world;
|
||||
float *time;
|
||||
float *frametime;
|
||||
int *newmis;
|
||||
float *force_retouch;
|
||||
string_t *mapname;
|
||||
float *deathmatch;
|
||||
float *coop;
|
||||
float *teamplay;
|
||||
float *serverflags;
|
||||
float *total_secrets;
|
||||
float *total_monsters;
|
||||
float *found_secrets;
|
||||
float *killed_monsters;
|
||||
float *parm1;
|
||||
float *parm2;
|
||||
float *parm3;
|
||||
float *parm4;
|
||||
float *parm5;
|
||||
float *parm6;
|
||||
float *parm7;
|
||||
float *parm8;
|
||||
float *parm9;
|
||||
float *parm10;
|
||||
float *parm11;
|
||||
float *parm12;
|
||||
float *parm13;
|
||||
float *parm14;
|
||||
float *parm15;
|
||||
float *parm16;
|
||||
vec3_t *V_v_forward;
|
||||
vec3_t *V_v_up;
|
||||
vec3_t *V_v_right;
|
||||
float *trace_allsolid;
|
||||
float *trace_startsolid;
|
||||
float *trace_fraction;
|
||||
vec3_t *V_trace_endpos;
|
||||
vec3_t *V_trace_plane_normal;
|
||||
float *trace_plane_dist;
|
||||
int *trace_ent;
|
||||
float *trace_inopen;
|
||||
float *trace_inwater;
|
||||
int *msg_entity;
|
||||
func_t *main;
|
||||
func_t *StartFrame;
|
||||
func_t *PlayerPreThink;
|
||||
func_t *PlayerPostThink;
|
||||
func_t *ClientKill;
|
||||
func_t *ClientConnect;
|
||||
func_t *PutClientInServer;
|
||||
func_t *ClientDisconnect;
|
||||
func_t *SetNewParms;
|
||||
func_t *SetChangeParms;
|
||||
float *cycle_wrapped;
|
||||
} nqglobalvars_t;
|
||||
|
||||
#define P_VEC(v) (pr_global_struct->V_##v)
|
||||
|
||||
typedef struct entvars_s
|
||||
{
|
||||
float modelindex;
|
||||
vec3_t absmin;
|
||||
vec3_t absmax;
|
||||
float ltime;
|
||||
float lastruntime;
|
||||
float movetype;
|
||||
float solid;
|
||||
vec3_t origin;
|
||||
vec3_t oldorigin;
|
||||
vec3_t velocity;
|
||||
vec3_t angles;
|
||||
vec3_t avelocity;
|
||||
string_t classname;
|
||||
string_t model;
|
||||
float frame;
|
||||
float skin;
|
||||
float effects;
|
||||
vec3_t mins;
|
||||
vec3_t maxs;
|
||||
vec3_t size;
|
||||
func_t touch;
|
||||
func_t use;
|
||||
func_t think;
|
||||
func_t blocked;
|
||||
float nextthink;
|
||||
int groundentity;
|
||||
float health;
|
||||
float frags;
|
||||
float weapon;
|
||||
string_t weaponmodel;
|
||||
float weaponframe;
|
||||
float currentammo;
|
||||
float ammo_shells;
|
||||
float ammo_nails;
|
||||
float ammo_rockets;
|
||||
float ammo_cells;
|
||||
float items;
|
||||
float takedamage;
|
||||
int chain;
|
||||
float deadflag;
|
||||
vec3_t view_ofs;
|
||||
float button0;
|
||||
float button1;
|
||||
float button2;
|
||||
float impulse;
|
||||
float fixangle;
|
||||
vec3_t v_angle;
|
||||
string_t netname;
|
||||
int enemy;
|
||||
float flags;
|
||||
float colormap;
|
||||
float team;
|
||||
float max_health;
|
||||
float teleport_time;
|
||||
float armortype;
|
||||
float armorvalue;
|
||||
float waterlevel;
|
||||
float watertype;
|
||||
float ideal_yaw;
|
||||
float yaw_speed;
|
||||
int aiment;
|
||||
int goalentity;
|
||||
float spawnflags;
|
||||
string_t target;
|
||||
string_t targetname;
|
||||
float dmg_take;
|
||||
float dmg_save;
|
||||
int dmg_inflictor;
|
||||
int owner;
|
||||
vec3_t movedir;
|
||||
float sounds;
|
||||
string_t noise;
|
||||
string_t noise1;
|
||||
string_t noise2;
|
||||
string_t noise3;
|
||||
|
||||
//extra vars. use these if you wish.
|
||||
float gravity;
|
||||
float maxspeed;
|
||||
float items2;
|
||||
float scale;
|
||||
float alpha;
|
||||
float fatness;
|
||||
int view2;
|
||||
float sendflags;
|
||||
float fteflags;
|
||||
vec3_t movement;
|
||||
float vweapmodelindex;
|
||||
|
||||
//dp extra fields
|
||||
int nodrawtoclient;
|
||||
int drawonlytoclient;
|
||||
|
||||
//udc_exeffect support. hacky I know.
|
||||
float seefcolour;
|
||||
float seefsizex;
|
||||
float seefsizey;
|
||||
float seefsizez;
|
||||
float seefoffset;
|
||||
|
||||
float playerclass; //hexen2 requirements
|
||||
float hull;
|
||||
float drawflags;
|
||||
|
||||
int movechain;
|
||||
func_t chainmoved;
|
||||
|
||||
float light_level;
|
||||
float abslight;
|
||||
|
||||
float level;
|
||||
float intelligence;
|
||||
float experience;
|
||||
float wisdom;
|
||||
float strength;
|
||||
float dexterity;
|
||||
float bluemana;
|
||||
float greenmana;
|
||||
float max_mana;
|
||||
float experiance;
|
||||
float artifact_active;
|
||||
float artifact_low;
|
||||
int cameramode;
|
||||
float rings_active;
|
||||
float rings_low;
|
||||
float armor_amulet;
|
||||
float armor_bracer;
|
||||
float armor_breastplate;
|
||||
float armor_helmet;
|
||||
float ring_flight;
|
||||
float ring_water;
|
||||
float ring_turning;
|
||||
float ring_regeneration;
|
||||
|
||||
string_t puzzle_inv1;
|
||||
string_t puzzle_inv2;
|
||||
string_t puzzle_inv3;
|
||||
string_t puzzle_inv4;
|
||||
string_t puzzle_inv5;
|
||||
string_t puzzle_inv6;
|
||||
string_t puzzle_inv7;
|
||||
string_t puzzle_inv8;
|
||||
|
||||
float hasted;
|
||||
float inventory;
|
||||
float cnt_torch;
|
||||
float cnt_h_boost;
|
||||
float cnt_sh_boost;
|
||||
float cnt_mana_boost;
|
||||
float cnt_teleport;
|
||||
float cnt_tome;
|
||||
float cnt_summon;
|
||||
float cnt_invisibility;
|
||||
float cnt_glyph;
|
||||
float cnt_haste;
|
||||
float cnt_blast;
|
||||
float cnt_polymorph;
|
||||
float cnt_flight;
|
||||
float cnt_cubeofforce;
|
||||
float cnt_invincibility;
|
||||
} entvars_t;
|
||||
|
||||
#define PROGHEADER_CRC 54730
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#define QCLIB //as opposed to standard qc stuff. One or other. All references+changes were by DMW unless specified otherwise. Starting 1/10/02
|
||||
|
||||
#define MAX_PROGS 64
|
||||
#define MAXADDONS 16
|
||||
|
||||
#define NewGetEdictFieldValue GetEdictFieldValue
|
||||
void Q_SetProgsParms(qboolean forcompiler);
|
||||
void PR_Deinit(void);
|
||||
void PR_LoadGlabalStruct(void);
|
||||
void Q_InitProgs(void);
|
||||
void PR_RegisterSVBuiltins(void);
|
||||
void PR_RegisterFields(void);
|
||||
void PR_Init(void);
|
||||
qboolean PR_UserCmd(char *cmd);
|
||||
|
||||
void PR_RunThreads(void);
|
||||
|
||||
|
||||
#define PR_MAINPROGS 0 //this is a constant that should really be phased out. But seeing as QCLIB requires some sort of master progs due to extern funcs...
|
||||
//maybe go through looking for extern funcs, and remember which were not allocated. It would then be a first come gets priority. Not too bad I supppose.
|
||||
|
||||
#include "progtype.h"
|
||||
#include "progdefs.h"
|
||||
|
||||
extern int compileactive;
|
||||
|
||||
typedef enum {PROG_NONE, PROG_QW, PROG_NQ, PROG_H2, PROG_UNKNOWN} progstype_t;
|
||||
extern progstype_t progstype;
|
||||
|
||||
|
||||
//extern globalvars_t *glob0;
|
||||
|
||||
extern int pr_edict_size;
|
||||
|
||||
|
||||
//extern progparms_t progparms;
|
||||
|
||||
//extern progsnum_t mainprogs;
|
||||
|
||||
#define MAX_ENT_LEAFS 16
|
||||
typedef struct edict_s
|
||||
{
|
||||
qboolean isfree;
|
||||
float freetime; // sv.time when the object was freed
|
||||
int entnum;
|
||||
qboolean readonly; //world
|
||||
link_t area; // linked to a division node or leaf
|
||||
|
||||
int solidtype;
|
||||
|
||||
int num_leafs;
|
||||
short leafnums[MAX_ENT_LEAFS];
|
||||
int areanum; //q2bsp
|
||||
int areanum2; //q2bsp
|
||||
int headnode; //q2bsp
|
||||
|
||||
entity_state_t baseline;
|
||||
|
||||
entvars_t v; // C exported fields from progs
|
||||
// other fields from progs come immediately after
|
||||
} edict_t;
|
||||
|
||||
|
||||
|
||||
#include "progslib.h"
|
||||
#define pr_trace *(svprogfuncs->pr_trace)
|
||||
|
||||
#undef pr_global_struct
|
||||
//#define pr_nqglobal_struct *((nqglobalvars_t*)pr_globals)
|
||||
#define pr_global_struct *pr_nqglobal_struct
|
||||
|
||||
extern nqglobalvars_t *pr_nqglobal_struct;
|
||||
|
||||
extern progfuncs_t *svprogfuncs; //instance
|
||||
extern progparms_t svprogparms;
|
||||
extern progsnum_t svmainprogs;
|
||||
extern progsnum_t clmainprogs;
|
||||
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
|
||||
#define Q2EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,q2edict_t,area)
|
||||
|
||||
extern func_t SpectatorConnect;
|
||||
extern func_t SpectatorThink;
|
||||
extern func_t SpectatorDisconnect;
|
||||
|
||||
extern func_t SV_PlayerPhysicsQC;
|
||||
extern func_t EndFrameQC;
|
||||
|
||||
qboolean PR_QCChat(char *text, int say_type);
|
||||
|
||||
|
||||
#ifndef SERVERONLY
|
||||
int CLPR_FindFunc(char *name);
|
||||
void CLPR_Init(void);
|
||||
void CLPR_DeinitProgs(void);
|
||||
#endif
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// game.h -- game dll information visible to server
|
||||
|
||||
typedef enum multicast_e
|
||||
{
|
||||
MULTICAST_ALL,
|
||||
MULTICAST_PHS,
|
||||
MULTICAST_PVS,
|
||||
MULTICAST_ALL_R,
|
||||
MULTICAST_PHS_R,
|
||||
MULTICAST_PVS_R
|
||||
} multicast_t;
|
||||
|
||||
extern float pm_stepheight;
|
||||
|
||||
#ifdef Q2SERVER
|
||||
|
||||
struct trace_s;
|
||||
struct q2trace_s;
|
||||
struct pmove_s;
|
||||
typedef struct pmove_s pmove_t;
|
||||
|
||||
|
||||
|
||||
|
||||
#define GAME_API_VERSION 3
|
||||
|
||||
// edict->svflags
|
||||
|
||||
#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
|
||||
#define SVF_DEADMONSTER 0x00000002 // treat as CONTENTS_DEADMONSTER for collision
|
||||
#define SVF_MONSTER 0x00000004 // treat as CONTENTS_MONSTER for collision
|
||||
|
||||
// edict->solid values
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Q2SOLID_NOT, // no interaction with other objects
|
||||
Q2SOLID_TRIGGER, // only touch when inside, after moving
|
||||
Q2SOLID_BBOX, // touch on edge
|
||||
Q2SOLID_BSP // bsp clip, touch on edge
|
||||
} q2solid_t;
|
||||
|
||||
|
||||
#define MAXTOUCH 32
|
||||
typedef struct
|
||||
{
|
||||
// state (in / out)
|
||||
q2pmove_state_t s;
|
||||
|
||||
// command (in)
|
||||
usercmd_t cmd;
|
||||
qboolean snapinitial; // if s has been changed outside pmove
|
||||
|
||||
// results (out)
|
||||
int numtouch;
|
||||
struct edict_s *touchents[MAXTOUCH];
|
||||
|
||||
vec3_t viewangles; // clamped
|
||||
float viewheight;
|
||||
|
||||
vec3_t mins, maxs; // bounding box size
|
||||
|
||||
struct edict_s *groundentity;
|
||||
int watertype;
|
||||
int waterlevel;
|
||||
|
||||
// callbacks to test the world
|
||||
q2trace_t (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
|
||||
int (*pointcontents) (vec3_t point);
|
||||
} q2pmove_t;
|
||||
|
||||
//===============================================================
|
||||
|
||||
// link_t is only used for entity area links now
|
||||
/*typedef struct link_s
|
||||
{
|
||||
struct link_s *prev, *next;
|
||||
} link_t;*/
|
||||
|
||||
#define MAX_ENT_CLUSTERS 16
|
||||
|
||||
|
||||
//typedef struct edict_s edict_t;
|
||||
typedef struct gclient_s gclient_t;
|
||||
|
||||
|
||||
#ifndef GAME_INCLUDE
|
||||
|
||||
struct q2gclient_s
|
||||
{
|
||||
q2player_state_t ps; // communicated by server to clients
|
||||
int ping;
|
||||
// the game dll can add anything it wants after
|
||||
// this point in the structure
|
||||
};
|
||||
|
||||
typedef struct q2entity_state_s
|
||||
{
|
||||
int number; // edict index
|
||||
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
vec3_t old_origin; // for lerping
|
||||
int modelindex;
|
||||
int modelindex2, modelindex3, modelindex4; // weapons, CTF flags, etc
|
||||
int frame;
|
||||
int skinnum;
|
||||
unsigned int effects; // PGM - we're filling it, so it needs to be unsigned
|
||||
int renderfx;
|
||||
int solid; // for client side prediction, 8*(bits 0-4) is x/y radius
|
||||
// 8*(bits 5-9) is z down distance, 8(bits10-15) is z up
|
||||
// gi.linkentity sets this properly
|
||||
int sound; // for looping sounds, to guarantee shutoff
|
||||
int event; // impulse events -- muzzle flashes, footsteps, etc
|
||||
// events only go out for a single frame, they
|
||||
// are automatically cleared each frame
|
||||
} q2entity_state_t;
|
||||
|
||||
|
||||
typedef struct q2edict_s q2edict_t;
|
||||
struct q2edict_s
|
||||
{
|
||||
q2entity_state_t s;
|
||||
struct q2gclient_s *client;
|
||||
qboolean inuse;
|
||||
int linkcount;
|
||||
|
||||
// FIXME: move these fields to a server private sv_entity_t
|
||||
link_t area; // linked to a division node or leaf
|
||||
|
||||
int num_clusters; // if -1, use headnode instead
|
||||
int clusternums[MAX_ENT_CLUSTERS];
|
||||
int headnode; // unused if num_clusters != -1
|
||||
int areanum, areanum2;
|
||||
|
||||
//================================
|
||||
|
||||
int svflags; // SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc
|
||||
vec3_t mins, maxs;
|
||||
vec3_t absmin, absmax, size;
|
||||
q2solid_t solid;
|
||||
int clipmask;
|
||||
q2edict_t *owner;
|
||||
|
||||
// the game dll can add anything it wants after
|
||||
// this point in the structure
|
||||
};
|
||||
|
||||
#endif // GAME_INCLUDE
|
||||
|
||||
//===============================================================
|
||||
|
||||
//
|
||||
// functions provided by the main engine
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
// special messages
|
||||
void (VARGS *bprintf) (int printlevel, char *fmt, ...);
|
||||
void (VARGS *dprintf) (char *fmt, ...);
|
||||
void (VARGS *cprintf) (q2edict_t *ent, int printlevel, char *fmt, ...);
|
||||
void (VARGS *centerprintf) (q2edict_t *ent, char *fmt, ...);
|
||||
void (*sound) (q2edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs);
|
||||
void (*positioned_sound) (vec3_t origin, q2edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs);
|
||||
|
||||
// config strings hold all the index strings, the lightstyles,
|
||||
// and misc data like the sky definition and cdtrack.
|
||||
// All of the current configstrings are sent to clients when
|
||||
// they connect, and changes are sent to all connected clients.
|
||||
void (*configstring) (int num, char *string);
|
||||
|
||||
void (VARGS *error) (char *fmt, ...);
|
||||
|
||||
// the *index functions create configstrings and some internal server state
|
||||
int (*modelindex) (char *name);
|
||||
int (*soundindex) (char *name);
|
||||
int (*imageindex) (char *name);
|
||||
|
||||
void (*setmodel) (q2edict_t *ent, char *name);
|
||||
|
||||
// collision detection
|
||||
q2trace_t (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, q2edict_t *passent, int contentmask);
|
||||
int (*pointcontents) (vec3_t point);
|
||||
qboolean (*inPVS) (vec3_t p1, vec3_t p2);
|
||||
qboolean (*inPHS) (vec3_t p1, vec3_t p2);
|
||||
void (*SetAreaPortalState) (int portalnum, qboolean open);
|
||||
qboolean (*AreasConnected) (int area1, int area2);
|
||||
|
||||
// an entity will never be sent to a client or used for collision
|
||||
// if it is not passed to linkentity. If the size, position, or
|
||||
// solidity changes, it must be relinked.
|
||||
void (*linkentity) (q2edict_t *ent);
|
||||
void (*unlinkentity) (q2edict_t *ent); // call before removing an interactive edict
|
||||
int (*BoxEdicts) (vec3_t mins, vec3_t maxs, q2edict_t **list, int maxcount, int areatype);
|
||||
void (*Pmove) (q2pmove_t *pmove); // player movement code common with client prediction
|
||||
|
||||
// network messaging
|
||||
void (*multicast) (vec3_t origin, multicast_t to);
|
||||
void (*unicast) (q2edict_t *ent, qboolean reliable);
|
||||
void (*WriteChar) (int c);
|
||||
void (*WriteByte) (int c);
|
||||
void (*WriteShort) (int c);
|
||||
void (*WriteLong) (int c);
|
||||
void (*WriteFloat) (float f);
|
||||
void (*WriteString) (char *s);
|
||||
void (*WritePosition) (vec3_t pos); // some fractional bits
|
||||
void (*WriteDir) (vec3_t pos); // single byte encoded, very coarse
|
||||
void (*WriteAngle) (float f);
|
||||
|
||||
// managed memory allocation
|
||||
void *(*TagMalloc) (int size, int tag);
|
||||
void (*TagFree) (void *block);
|
||||
void (*FreeTags) (int tag);
|
||||
|
||||
// console variable interaction
|
||||
cvar_t *(*cvar) (char *var_name, char *value, int flags);
|
||||
cvar_t *(*cvar_set) (char *var_name, char *value);
|
||||
cvar_t *(*cvar_forceset) (char *var_name, char *value);
|
||||
|
||||
// ClientCommand and ServerCommand parameter access
|
||||
int (*argc) (void);
|
||||
char *(*argv) (int n);
|
||||
char *(*args) (void); // concatenation of all argv >= 1
|
||||
|
||||
// add commands to the server console as if they were typed in
|
||||
// for map changing, etc
|
||||
void (*AddCommandString) (char *text);
|
||||
|
||||
void (*DebugGraph) (float value, int color);
|
||||
} game_import_t;
|
||||
|
||||
//
|
||||
// functions exported by the game subsystem
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
int apiversion;
|
||||
|
||||
// the init function will only be called when a game starts,
|
||||
// not each time a level is loaded. Persistant data for clients
|
||||
// and the server can be allocated in init
|
||||
void (*Init) (void);
|
||||
void (*Shutdown) (void);
|
||||
|
||||
// each new level entered will cause a call to SpawnEntities
|
||||
void (*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint);
|
||||
|
||||
// Read/Write Game is for storing persistant cross level information
|
||||
// about the world state and the clients.
|
||||
// WriteGame is called every time a level is exited.
|
||||
// ReadGame is called on a loadgame.
|
||||
void (*WriteGame) (char *filename, qboolean autosave);
|
||||
void (*ReadGame) (char *filename);
|
||||
|
||||
// ReadLevel is called after the default map information has been
|
||||
// loaded with SpawnEntities
|
||||
void (*WriteLevel) (char *filename);
|
||||
void (*ReadLevel) (char *filename);
|
||||
|
||||
qboolean (*ClientConnect) (q2edict_t *ent, char *userinfo);
|
||||
void (*ClientBegin) (q2edict_t *ent);
|
||||
void (*ClientUserinfoChanged) (q2edict_t *ent, char *userinfo);
|
||||
void (*ClientDisconnect) (q2edict_t *ent);
|
||||
void (*ClientCommand) (q2edict_t *ent);
|
||||
void (*ClientThink) (q2edict_t *ent, usercmd_t *cmd);
|
||||
|
||||
void (*RunFrame) (void);
|
||||
|
||||
// ServerCommand will be called when an "sv <command>" command is issued on the
|
||||
// server console.
|
||||
// The game can issue gi.argc() / gi.argv() commands to get the rest
|
||||
// of the parameters
|
||||
void (*ServerCommand) (void);
|
||||
|
||||
//
|
||||
// global variables shared between game and server
|
||||
//
|
||||
|
||||
// The edict array is allocated in the game dll so it
|
||||
// can vary in size from one game to another.
|
||||
//
|
||||
// The size will be fixed when ge->Init() is called
|
||||
struct q2edict_s *edicts;
|
||||
int edict_size;
|
||||
int num_edicts; // current number, <= max_edicts
|
||||
int max_edicts;
|
||||
} game_export_t;
|
||||
|
||||
game_export_t *GetGameApi (game_import_t *import);
|
||||
|
||||
|
||||
|
||||
extern game_export_t *ge;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// quakedef.h -- primary header for server
|
||||
#define QUAKEDEF_H__
|
||||
#if 1//ndef SERVERONLY
|
||||
#include "../client/quakedef.h"
|
||||
#else
|
||||
|
||||
#define QUAKE_GAME // as opposed to utilities
|
||||
|
||||
//define PARANOID // speed sapping error checking
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "bothdefs.h"
|
||||
|
||||
#ifdef MSVCDISABLEWARNINGS
|
||||
#pragma warning( disable : 4244 4127 4201 4214 4514 4305 4115 4018)
|
||||
#endif
|
||||
|
||||
#include "translate.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "bspfile.h"
|
||||
#include "sys.h"
|
||||
#include "zone.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
#include "cvar.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
#include "cmd.h"
|
||||
#include "model.h"
|
||||
#include "crc.h"
|
||||
#include "progs.h"
|
||||
#include "q2game.h"
|
||||
|
||||
#include "server.h"
|
||||
#include "world.h"
|
||||
#include "pmove.h"
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// the host system specifies the base of the directory tree, the
|
||||
// command line parms passed to the program, and the amount of memory
|
||||
// available for the program to use
|
||||
|
||||
typedef struct quakeparms_s
|
||||
{
|
||||
char *basedir;
|
||||
char *cachedir; // for development over ISDN lines
|
||||
int argc;
|
||||
char **argv;
|
||||
void *membase;
|
||||
int memsize;
|
||||
} quakeparms_t;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
//
|
||||
// host
|
||||
//
|
||||
extern quakeparms_t host_parms;
|
||||
|
||||
extern cvar_t sys_nostdout;
|
||||
extern cvar_t developer;
|
||||
|
||||
extern qboolean host_initialized; // true if into command execution
|
||||
extern double host_frametime;
|
||||
extern double realtime; // not bounded in any way, changed at
|
||||
// start of every frame, never reset
|
||||
|
||||
void SV_Error (char *error, ...);
|
||||
void SV_Init (struct quakeparms_s *parms);
|
||||
|
||||
void Con_Printf (char *fmt, ...);
|
||||
void Con_TPrintf (translation_t fmt, ...);
|
||||
void Con_DPrintf (char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,644 @@
|
|||
#include "qwsvdef.h"
|
||||
|
||||
/*
|
||||
NPC chat:
|
||||
The idea is that the server reads in a text file, calls qc functions as appropriate, and centerprints the result to the corresponding player.
|
||||
All play is paused while the chat is in progress.
|
||||
There are no guarentees that this is useful to anyone. If it does sound sorta what you want and would like a small change then just ask.
|
||||
|
||||
The options are specified with commas between. a number specifies a tag, anything else is assumed to be a statement/function,
|
||||
which is carried out when the text is used (rather than when it is mearly an option).
|
||||
statements can be functions, addition, multiplication, division, subtraction. Storing is also possible.
|
||||
To store, you need to name a variable (which will be created when used). The variable must be a float.
|
||||
Strings will work ONLY when specified without arithmatic, and ONLY in function calls.
|
||||
You can call QC functions which accept entities on the condition that the entity accepted is the player entity that is being used for the menu.
|
||||
If you want to keep track of the person you are chatting to, use an entity field for it.
|
||||
To pass this entity, use the word 'ent', without quotes of any kind.
|
||||
Do not use operators or calls within a function call. It's not that advanced. You can use operators on the condition that you use and name a temp.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Exmaple dialog script:
|
||||
dialog/barry.dlg:
|
||||
|
||||
#tag/number, condition (float(entity ent) cond;), text, options.
|
||||
#if options has a function, that is called. Multiple options/funcs can be done with commas. No options will terminate. If a reply has multiple options, a random (non function) is picked.
|
||||
#no distinction between characture speech and player options.
|
||||
#char statements ignore condition.
|
||||
|
||||
#the first entry point
|
||||
{0}{}{So that slip-gate does work then. Hmph. Maybe they just turned the power back on! So, what can I do you for?}{1, 2, 3}
|
||||
{1}{}{Whu? Who are you?! Where am I?!}{10}
|
||||
{2}{}{Who ever you are, now you die!}{20}
|
||||
{3}{}{Oh, err, nothing. I know the story line already. Sorry.}{4}
|
||||
{4}{}{KNOW IT ALL!}{}
|
||||
|
||||
{10}{}{You are in a place that we dub the 'Shambles', a resource drained town. We havn't managed to rebuild our society since the Destroyer dude came through here, killing anyone before they could ask why. We even had anarcy! Boy, that was fun! Anyway, who are you?}{11, 12}
|
||||
{11}{}{I'm just some random guy who was walking a dog. Then I got trapped behind a rock fall and found this really old place all boarded up. Next I knew I was here! I think I killed my dog though...}{30}
|
||||
{12}{}{Why the hell do you care! I'm just goin' to kill you now!}{20}
|
||||
|
||||
{20}{}{That's just not nice!}{BarryWar(), give_arrogance(ent, 100), give_evil(ent, 500)}
|
||||
|
||||
{30}{}{Do you reckon that you're much good with explosives? It's just that our church yard is a little over-run with zombies. You know how it is when some-one knicks your runes! I'm just asking, cos we don't much like cremation around here. It's a waste of fertilliser!}{31, 32, 33}
|
||||
{31}{}{I rekon you could blast 'em into chunky kibbles better than I.}{40}
|
||||
{32}{has_grenadelauncher(ent)}{I'll go right now!}{}
|
||||
{33}{!has_grenadelauncher(ent)}{Well, I would, but seeing as I ain't got a grenade launcher, I can't}{50}
|
||||
|
||||
{40}{}{Yeah, probably. Bye!}{}
|
||||
|
||||
{50}{}{That could be a problem couldn't it. Ah well, here, have my spare Rocket Launcher. I'm meant to use it against any nasties that come through that gate, but we havn't had anyone except you for years!}{give_weapon_rocketlauncher(ent), give_cunning(ent 100)}
|
||||
|
||||
#second entry point (use a tag parameter of 200)
|
||||
{200}{}{I'm sorry, I can't help you in any way.}{}
|
||||
|
||||
|
||||
|
||||
|
||||
the qc code:
|
||||
void(string name, float tag, entity player) Chat = #214;
|
||||
|
||||
void() SomeMonstersTouchFunction =
|
||||
{
|
||||
Chat("barry", 0, other);
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef SVCHAT
|
||||
|
||||
#define SENDDELAY 1
|
||||
|
||||
float SV_ChatFunc(char *func);
|
||||
void Chat_GetTag(char *filename, float tag, char **text, char **condition, char **options)
|
||||
{
|
||||
char *file; char *s;
|
||||
file = COM_LoadTempFile(va("dialog/%s.dlg", filename));
|
||||
if (!file)
|
||||
{
|
||||
*text = "ERROR: File not found";
|
||||
*condition = "";
|
||||
*options = "";
|
||||
return;
|
||||
}
|
||||
for (;*file;file++)
|
||||
{
|
||||
if (*file == '\n')
|
||||
{
|
||||
if (file[1] == '{')
|
||||
{
|
||||
if(atof(file+2)==tag)
|
||||
{
|
||||
*condition = strchr(file+2, '{')+1;
|
||||
|
||||
s = strchr(file, '|');
|
||||
if (s && s < *condition)
|
||||
{
|
||||
*text = strchr(s, '}');
|
||||
**text = '\0';
|
||||
|
||||
if (!SV_ChatFunc(s+1))
|
||||
{
|
||||
**text='}';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
s = strchr(*condition, '}');
|
||||
*s = '\0';
|
||||
|
||||
*text = strchr(s+1, '{')+1;
|
||||
s = strchr(*text, '}');
|
||||
*s = '\0';
|
||||
|
||||
*options = strchr(s+1, '{')+1;
|
||||
s = strchr(*options, '}');
|
||||
*s = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Sys_Error("Tag %f not found in file %s", tag, host_client->chat.filename);
|
||||
}
|
||||
|
||||
chatvar_t *SV_ChatFindVariable(char *name)
|
||||
{
|
||||
chatvar_t *cvar;
|
||||
cvar = host_client->chat.vars;
|
||||
while (cvar)
|
||||
{
|
||||
if (!strcmp(cvar->varname, name))
|
||||
return cvar;
|
||||
|
||||
cvar = cvar->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float SV_ChatGetValue(char *name)
|
||||
{
|
||||
chatvar_t *cvar;
|
||||
if ((*name >= '0' && *name <= '9') || *name == '-')
|
||||
return atof(name);
|
||||
if (!strcmp(name, "true"))
|
||||
return 1;
|
||||
if (!strcmp(name, "false"))
|
||||
return 0;
|
||||
cvar = SV_ChatFindVariable(name);
|
||||
if (cvar)
|
||||
return cvar->value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
float SV_ChatSetValue(char *name, float newval)
|
||||
{
|
||||
chatvar_t *cvar;
|
||||
cvar = SV_ChatFindVariable(name);
|
||||
if (cvar)
|
||||
{
|
||||
cvar->value = newval;
|
||||
return newval;
|
||||
}
|
||||
cvar = Z_Malloc(sizeof(chatvar_t));
|
||||
strcpy(cvar->varname, name);
|
||||
cvar->value = newval;
|
||||
cvar->next = host_client->chat.vars;
|
||||
host_client->chat.vars = cvar;
|
||||
|
||||
return newval;
|
||||
}
|
||||
|
||||
float SV_ChatFunc(char *func) //parse a condition/function
|
||||
{
|
||||
globalvars_t *pr_globals;
|
||||
float result;
|
||||
int noted = false;
|
||||
char *s, *os, namebuf[64];
|
||||
func_t f;
|
||||
int parm;
|
||||
while (*func <= ' ')
|
||||
func++;
|
||||
if (*func == '!')
|
||||
{
|
||||
noted = true;
|
||||
func++;
|
||||
}
|
||||
s = COM_ParseToken(func);
|
||||
if (*com_token == '(')
|
||||
{//open bracket
|
||||
//find correct close
|
||||
parm = 1;
|
||||
for (s = func+1; ; s++)
|
||||
{
|
||||
if (!*s)
|
||||
Sys_Error("No close bracket");
|
||||
if (*s == ')')
|
||||
{
|
||||
parm--;
|
||||
if (!parm)break;
|
||||
}
|
||||
if (*s == '(')
|
||||
parm++;
|
||||
}
|
||||
func = strchr(func, '(');
|
||||
s=COM_ParseToken(s+1);
|
||||
if (!strncmp(com_token, "&&", 2))
|
||||
result = SV_ChatFunc(func+1) && SV_ChatFunc(s);
|
||||
else if (!strncmp(com_token, "||", 2))
|
||||
result = SV_ChatFunc(func+1) || SV_ChatFunc(s);
|
||||
else
|
||||
result = SV_ChatFunc(func+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(namebuf, com_token); //get first word
|
||||
|
||||
while (*s <= ' ')
|
||||
s++;
|
||||
|
||||
if (*s == '(') //if followed by brackets
|
||||
{
|
||||
s++;
|
||||
pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
|
||||
parm = OFS_PARM0;
|
||||
while((s=COM_ParseToken(os = s)))
|
||||
{
|
||||
if (*com_token == ')')
|
||||
break;
|
||||
if (*com_token == ',')
|
||||
continue;
|
||||
if (com_tokentype == TTP_STRING)
|
||||
G_INT(parm) = (int)PR_NewString(svprogfuncs, com_token);
|
||||
else if (!strcmp(com_token, "ent"))
|
||||
SetGlobalEdict(svprogfuncs, host_client->chat.edict, parm);
|
||||
else
|
||||
G_FLOAT(parm) = SV_ChatFunc(os);
|
||||
|
||||
parm+=OFS_PARM1-OFS_PARM0;
|
||||
}
|
||||
|
||||
f = PR_FindFunction(svprogfuncs, namebuf, PR_CURRENT);
|
||||
if (f)
|
||||
{
|
||||
PR_ExecuteProgram(svprogfuncs, f);
|
||||
}
|
||||
else
|
||||
Con_Printf("Failed to find function %s\n", namebuf);
|
||||
|
||||
pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
|
||||
result = G_FLOAT(OFS_RETURN);
|
||||
}
|
||||
else
|
||||
{
|
||||
//comparision operators
|
||||
if (!strncmp(s, "==", 2))
|
||||
result = (SV_ChatGetValue(namebuf) == SV_ChatFunc(s+2));
|
||||
else if (!strncmp(s, ">=", 2))
|
||||
result = (SV_ChatGetValue(namebuf) >= SV_ChatFunc(s+2));
|
||||
else if (!strncmp(s, "<=", 2))
|
||||
result = (SV_ChatGetValue(namebuf) <= SV_ChatFunc(s+2));
|
||||
else if (!strncmp(s, "!=", 2))
|
||||
result = (SV_ChatGetValue(namebuf) != SV_ChatFunc(s+2));
|
||||
else if (!strncmp(s, ">", 1))
|
||||
result = (SV_ChatGetValue(namebuf) >= SV_ChatFunc(s+2));
|
||||
else if (!strncmp(s, "<", 1))
|
||||
result = (SV_ChatGetValue(namebuf) <= SV_ChatFunc(s+2));
|
||||
|
||||
//asignment operators
|
||||
else if (!strncmp(s, "=", 1))
|
||||
result = (SV_ChatSetValue(namebuf, SV_ChatFunc(s+1)));
|
||||
else if (!strncmp(s, "+=", 2))
|
||||
result = (SV_ChatSetValue(namebuf, SV_ChatGetValue(namebuf)+SV_ChatFunc(s+2)));
|
||||
else if (!strncmp(s, "-=", 2))
|
||||
result = (SV_ChatSetValue(namebuf, SV_ChatGetValue(namebuf)-SV_ChatFunc(s+2)));
|
||||
else if (!strncmp(s, "*=", 2))
|
||||
result = (SV_ChatSetValue(namebuf, SV_ChatGetValue(namebuf)*SV_ChatFunc(s+2)));
|
||||
else if (!strncmp(s, "/=", 2))
|
||||
result = (SV_ChatSetValue(namebuf, SV_ChatGetValue(namebuf)/SV_ChatFunc(s+2)));
|
||||
else if (!strncmp(s, "|=", 2))
|
||||
result = (SV_ChatSetValue(namebuf, (int)SV_ChatGetValue(namebuf)|(int)SV_ChatFunc(s+2)));
|
||||
else if (!strncmp(s, "&=", 2))
|
||||
result = (SV_ChatSetValue(namebuf, (int)SV_ChatGetValue(namebuf)&(int)SV_ChatFunc(s+2)));
|
||||
|
||||
//mathematical operators
|
||||
else if (!strncmp(s, "+", 1))
|
||||
result = ( SV_ChatGetValue(namebuf)+SV_ChatFunc(s+1));
|
||||
else if (!strncmp(s, "-", 1))
|
||||
result = (SV_ChatGetValue(namebuf)-SV_ChatFunc(s+1));
|
||||
else if (!strncmp(s, "*", 1))
|
||||
result = (SV_ChatGetValue(namebuf)*SV_ChatFunc(s+1));
|
||||
else if (!strncmp(s, "/", 1))
|
||||
result = (SV_ChatGetValue(namebuf)/SV_ChatFunc(s+1));
|
||||
else if (!strncmp(s, "|", 1))
|
||||
result = ((int)SV_ChatGetValue(namebuf)|(int)SV_ChatFunc(s+1));
|
||||
else if (!strncmp(s, "&", 1))
|
||||
result = ((int)SV_ChatGetValue(namebuf)&(int)SV_ChatFunc(s+1));
|
||||
|
||||
//operatorless
|
||||
else
|
||||
result = SV_ChatGetValue(namebuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (noted)
|
||||
result = !result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void SV_SendChat(void)
|
||||
{
|
||||
int l;
|
||||
int i;
|
||||
char *s, *s2, *text;
|
||||
|
||||
l = 2 + strlen(host_client->chat.maintext)+2;
|
||||
for (i = 0; i < host_client->chat.options; i++)
|
||||
l += strlen(host_client->chat.option[i].text)+2;
|
||||
|
||||
s = Z_Malloc(l+1);
|
||||
s2 = s;
|
||||
text = host_client->chat.maintext;
|
||||
while(*text)
|
||||
{
|
||||
*s2 = *text ^ 128;
|
||||
text++;
|
||||
s2++;
|
||||
}
|
||||
*s2='\n';
|
||||
*s2++;
|
||||
*s2='\n';
|
||||
*s2++;
|
||||
*s2='\0';
|
||||
for (i = 0; i < host_client->chat.options; i++)
|
||||
{
|
||||
strcat(s2, host_client->chat.option[i].text);
|
||||
strcat(s2, "\n\n");
|
||||
}
|
||||
|
||||
|
||||
ClientReliableWrite_Begin (host_client, svc_centerprint, 2 + l);
|
||||
ClientReliableWrite_String (host_client, s);
|
||||
|
||||
/*
|
||||
MSG_WriteByte(&sv.reliable_datagram, svc_chat);
|
||||
if (!*host_client->chat.maintext) //no text. don't mix with ends
|
||||
MSG_WriteString(&sv.reliable_datagram, " ");
|
||||
else
|
||||
MSG_WriteString(&sv.reliable_datagram, host_client->chat.maintext);
|
||||
|
||||
MSG_WriteByte(&sv.reliable_datagram, i);
|
||||
for (i = 0; i < host_client->chat.options; i++)
|
||||
MSG_WriteString(&sv.reliable_datagram, host_client->chat.option[i].text);
|
||||
*/
|
||||
|
||||
host_client->chat.time = sv.time+SENDDELAY;
|
||||
}
|
||||
void SV_EndChat(void)
|
||||
{
|
||||
host_client->chat.active = false;
|
||||
host_client->chat.time=0;
|
||||
|
||||
ClientReliableWrite_Begin (host_client, svc_centerprint, 2);
|
||||
ClientReliableWrite_String (host_client, "");
|
||||
/*
|
||||
MSG_WriteByte(&sv.reliable_datagram, svc_chat);
|
||||
MSG_WriteString(&sv.reliable_datagram, "");
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void SV_Chat(char *filename, float starttag, edict_t *edict)
|
||||
{
|
||||
int i, tag;
|
||||
char optiontext[1024];
|
||||
char *text; char *condition; char *options;
|
||||
char *s, *s2;
|
||||
if (host_client->chat.active)
|
||||
return;
|
||||
host_client->chat.active = true;
|
||||
|
||||
host_client->chat.edict = edict;
|
||||
strcpy(host_client->chat.filename, filename);
|
||||
Chat_GetTag(filename, starttag, &text, &condition, &options);
|
||||
strcpy(host_client->chat.maintext, text);
|
||||
|
||||
strcpy(optiontext, options);
|
||||
|
||||
|
||||
s = optiontext;
|
||||
for (i = 0; i < 6 && s; )
|
||||
{
|
||||
if (!*s)
|
||||
break;
|
||||
for (s2=s;;s2++)
|
||||
{
|
||||
if (*s2 == ',')
|
||||
{
|
||||
*s2='\0';
|
||||
s2++;
|
||||
break;
|
||||
}
|
||||
if (*s2 == '\0')
|
||||
{
|
||||
s2=NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (*s <= ' ')
|
||||
s++;
|
||||
|
||||
if ((*s >= '0' && *s <= '9') || (*s == '-' && s[1] >= '0' && s[1] <= '9'))
|
||||
{
|
||||
tag = atof(s);
|
||||
Chat_GetTag(filename, tag, &text, &condition, &options);
|
||||
strcpy(host_client->chat.option[i].text, text);
|
||||
host_client->chat.option[i].tag = tag;
|
||||
|
||||
if (*condition)
|
||||
{
|
||||
if (SV_ChatFunc(condition))
|
||||
i++;
|
||||
/*
|
||||
if (*condition == '!'){noted=true;condition++;}else noted=false;
|
||||
f = PR_FindFunction(condition, PR_CURRENT);
|
||||
if (f)
|
||||
{
|
||||
SetGlobalEdict(sv.chat.edict, OFS_PARM0);
|
||||
PR_ExecuteProgram(f);
|
||||
pr_globals = PR_globals(PR_CURRENT);
|
||||
if (noted)
|
||||
{
|
||||
if (!G_FLOAT(OFS_RETURN))
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (G_FLOAT(OFS_RETURN))
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf("Function \"%s\" was not found (for chat condition). Assumed true.\n", condition);
|
||||
i++;
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
SV_ChatFunc(s);
|
||||
/*
|
||||
f = PR_FindFunction(s, PR_CURRENT);
|
||||
if (f)
|
||||
{
|
||||
SetGlobalEdict(sv.chat.edict, OFS_PARM0);
|
||||
PR_ExecuteProgram(f);
|
||||
}
|
||||
else
|
||||
Con_Printf("Function \"%s\" was not found (for chat)\n", s);
|
||||
*/
|
||||
}
|
||||
|
||||
s = s2;
|
||||
}
|
||||
|
||||
host_client->chat.options=i;
|
||||
|
||||
SV_SendChat();
|
||||
}
|
||||
|
||||
void SV_RecieveChat(int sel)
|
||||
{
|
||||
char *text;
|
||||
char *condition;
|
||||
char *options, *s, *s2;
|
||||
float tag;
|
||||
if (!host_client->chat.active)
|
||||
return;
|
||||
if (host_client->chat.options == 0)
|
||||
{
|
||||
SV_EndChat();
|
||||
return;
|
||||
}
|
||||
|
||||
sel = host_client->chat.option[sel-1].tag;
|
||||
|
||||
Chat_GetTag(host_client->chat.filename, sel, &text, &condition, &options);
|
||||
tag = -1;
|
||||
for (s = options;s; )
|
||||
{
|
||||
if (!*s)
|
||||
break;
|
||||
for (s2=s;;s2++)
|
||||
{
|
||||
if (*s2 == ',')
|
||||
{
|
||||
*s2='\0';
|
||||
s2++;
|
||||
break;
|
||||
}
|
||||
if (*s2 == '\0')
|
||||
{
|
||||
s2=NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*s >= '0' && *s <= '9') || *s <= ' ')
|
||||
{
|
||||
tag = atof(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
SV_ChatFunc(s);
|
||||
/*
|
||||
f = PR_FindFunction(s, PR_CURRENT);
|
||||
if (f)
|
||||
{
|
||||
// *progfuncs->pr_trace = 2;
|
||||
SetGlobalEdict(sv.chat.edict, OFS_PARM0);
|
||||
PR_ExecuteProgram(f);
|
||||
}
|
||||
else
|
||||
Con_Printf("Function \"%s\" was not found (for chat)\n", s);
|
||||
*/
|
||||
}
|
||||
|
||||
s = s2;
|
||||
}
|
||||
|
||||
if (tag < 0)
|
||||
{
|
||||
SV_EndChat();
|
||||
return;
|
||||
}
|
||||
|
||||
host_client->chat.active=false;
|
||||
SV_Chat(host_client->chat.filename, tag, host_client->chat.edict);
|
||||
}
|
||||
|
||||
//new game
|
||||
void SV_WipeChat(client_t *client)
|
||||
{
|
||||
chatvar_t *var;
|
||||
chatvar_t *lastvar = NULL;
|
||||
for (var = client->chat.vars; var; var=var->next)
|
||||
{
|
||||
if (lastvar)
|
||||
Z_Free(lastvar);
|
||||
lastvar = var;
|
||||
}
|
||||
if (lastvar)
|
||||
Z_Free(lastvar);
|
||||
|
||||
client->chat.active = false;
|
||||
client->chat.vars = NULL;
|
||||
}
|
||||
|
||||
//end of level. Maybe not though.
|
||||
char *SV_SaveChat(void) //is malloc. Clear old before call.
|
||||
{
|
||||
chatvar_t *var;
|
||||
char *buf, *start;
|
||||
int bufsize=0;
|
||||
char tbuf[64];
|
||||
buf = tbuf;
|
||||
for (var = host_client->chat.vars; var; var=var->next)
|
||||
{
|
||||
bufsize += strlen(var->varname);
|
||||
sprintf(buf, "=%f;", var->value);
|
||||
bufsize += strlen(buf);
|
||||
}
|
||||
bufsize++;
|
||||
start = buf = BZ_Malloc(bufsize);
|
||||
|
||||
for (var = host_client->chat.vars; var; var=var->next)
|
||||
{
|
||||
strcpy(buf, var->varname);
|
||||
buf += strlen(var->varname);
|
||||
sprintf(buf, "=%f;", var->value);
|
||||
buf += strlen(buf);
|
||||
}
|
||||
*buf = 0;
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
//beginning of new level.
|
||||
void SV_LoadChat(char *buffer)
|
||||
{
|
||||
char namebuf[64], value[64];
|
||||
char *start, *eq, *end;
|
||||
SV_WipeChat(host_client);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
start = buffer;
|
||||
for(;;)
|
||||
{
|
||||
eq = strchr(start, '=');
|
||||
if (!eq)
|
||||
break;
|
||||
end = strchr(eq, ';');
|
||||
if (!end)
|
||||
break;
|
||||
|
||||
Q_strncpyz(namebuf, start, eq-start);
|
||||
Q_strncpyz(value, eq+1, end-(eq+1));
|
||||
SV_ChatSetValue(namebuf, atof(value));
|
||||
start = end + 1;
|
||||
while (*start <= ' ')
|
||||
{
|
||||
if (*start == '\0')
|
||||
break;
|
||||
start++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int SV_ChatMove(int impulse)
|
||||
{
|
||||
if (host_client->chat.active && impulse)
|
||||
SV_RecieveChat(impulse);
|
||||
return false;
|
||||
}
|
||||
void SV_ChatThink(client_t *client)
|
||||
{
|
||||
if (client->chat.active && client->chat.time < sv.time) //centerprint wears off. Resend every few secs.
|
||||
{
|
||||
host_client = client;
|
||||
SV_SendChat();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue