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:
Spoike 2004-08-23 00:15:46 +00:00
parent b3fb01bfed
commit 8184225473
117 changed files with 103695 additions and 0 deletions

181
engine/client/anorms.h Normal file
View File

@ -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},

481
engine/client/cd_win.c Normal file
View File

@ -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");
}

31
engine/client/cdaudio.h Normal file
View File

@ -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);

527
engine/client/cl_cam.c Normal file
View File

@ -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);
}

1120
engine/client/cl_demo.c Normal file

File diff suppressed because it is too large Load Diff

2111
engine/client/cl_ents.c Normal file

File diff suppressed because it is too large Load Diff

1140
engine/client/cl_input.c Normal file

File diff suppressed because it is too large Load Diff

2683
engine/client/cl_main.c Normal file

File diff suppressed because it is too large Load Diff

100
engine/client/cl_master.h Normal file
View File

@ -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);

4022
engine/client/cl_parse.c Normal file

File diff suppressed because it is too large Load Diff

726
engine/client/cl_pred.c Normal file
View File

@ -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);
}

1360
engine/client/cl_screen.c Normal file

File diff suppressed because it is too large Load Diff

1892
engine/client/cl_tent.c Normal file

File diff suppressed because it is too large Load Diff

1344
engine/client/cl_ui.c Normal file

File diff suppressed because it is too large Load Diff

813
engine/client/client.h Normal file
View File

@ -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);

536
engine/client/clq2_cin.c Normal file
View File

@ -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

1762
engine/client/clq2_ents.c Normal file

File diff suppressed because it is too large Load Diff

1176
engine/client/console.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

469
engine/client/fragstats.c Normal file
View File

@ -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");
}

1739
engine/client/image.c Normal file

File diff suppressed because it is too large Load Diff

1791
engine/client/in_win.c Normal file

File diff suppressed because it is too large Load Diff

40
engine/client/input.h Normal file
View File

@ -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

1334
engine/client/keys.c Normal file

File diff suppressed because it is too large Load Diff

172
engine/client/keys.h Normal file
View File

@ -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);

1289
engine/client/m_items.c Normal file

File diff suppressed because it is too large Load Diff

800
engine/client/m_master.c Normal file
View File

@ -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

2102
engine/client/m_mp3.c Normal file

File diff suppressed because it is too large Load Diff

377
engine/client/m_multi.c Normal file
View File

@ -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

425
engine/client/m_options.c Normal file
View File

@ -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);
}

220
engine/client/m_script.c Normal file
View File

@ -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");
}

483
engine/client/m_single.c Normal file
View File

@ -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, "");
}

971
engine/client/menu.c Normal file
View File

@ -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;
}
}

282
engine/client/menu.h Normal file
View File

@ -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);

107
engine/client/merged.h Normal file
View File

@ -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

164
engine/client/modelgen.h Normal file
View File

@ -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"

980
engine/client/net_master.c Normal file
View File

@ -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

BIN
engine/client/q2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

181
engine/client/q2anorms.h Normal file
View File

@ -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},

247
engine/client/quakedef.h Normal file
View File

@ -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

612
engine/client/r_bulleten.c Normal file
View File

@ -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

View File

@ -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);

289
engine/client/r_efrag.c Normal file
View File

@ -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);
// }
}
}

2565
engine/client/r_part.c Normal file

File diff suppressed because it is too large Load Diff

1168
engine/client/r_partset.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

345
engine/client/render.h Normal file
View File

@ -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;

1449
engine/client/renderer.c Normal file

File diff suppressed because it is too large Load Diff

98
engine/client/renderque.c Normal file
View File

@ -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;
}

11
engine/client/renderque.h Normal file
View File

@ -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;

23
engine/client/resource.h Normal file
View File

@ -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

622
engine/client/roq_read.c Normal file
View File

@ -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

2246
engine/client/sbar.c Normal file

File diff suppressed because it is too large Load Diff

47
engine/client/sbar.h Normal file
View File

@ -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);

81
engine/client/screen.H Normal file
View File

@ -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);

424
engine/client/skin.c Normal file
View File

@ -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;
}
}

1718
engine/client/snd_dma.c Normal file

File diff suppressed because it is too large Load Diff

434
engine/client/snd_mem.c Normal file
View File

@ -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

986
engine/client/snd_mix.c Normal file
View File

@ -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

225
engine/client/snd_mixa.s Normal file
View File

@ -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

497
engine/client/snd_mp3.c Normal file
View File

@ -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

250
engine/client/snd_ov.c Normal file
View File

@ -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

1358
engine/client/snd_win.c Normal file

File diff suppressed because it is too large Load Diff

260
engine/client/sound.h Normal file
View File

@ -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

138
engine/client/spritegn.h Normal file
View File

@ -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;

938
engine/client/sys_win.c Normal file
View File

@ -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

118
engine/client/sys_wina.s Normal file
View File

@ -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

459
engine/client/teamplay.c Normal file
View File

@ -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

992
engine/client/textedit.c Normal file
View File

@ -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

654
engine/client/valid.c Normal file
View File

@ -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");
}
}

144
engine/client/vid.h Normal file
View File

@ -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

1850
engine/client/view.c Normal file

File diff suppressed because it is too large Load Diff

35
engine/client/view.h Normal file
View File

@ -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);

582
engine/client/wad.c Normal file
View File

@ -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;
}

85
engine/client/wad.h Normal file
View File

@ -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);

195
engine/client/winquake.h Normal file
View File

@ -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

127
engine/client/winquake.rc Normal file
View File

@ -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

2435
engine/client/zqtp.c Normal file

File diff suppressed because it is too large Load Diff

99
engine/common/console.h Normal file
View File

@ -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

73
engine/common/particles.h Normal file
View File

@ -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

773
engine/common/protocol.h Normal file
View File

@ -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

1005
engine/common/qvm.c Normal file

File diff suppressed because it is too large Load Diff

84
engine/common/sys.h Normal file
View File

@ -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);

832
engine/common/translate.c Normal file
View File

@ -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];
}

351
engine/common/translate.h Normal file
View File

@ -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

174
engine/common/ui_public.h Normal file
View File

@ -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;

61
engine/common/vm.h Normal file
View File

@ -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

143
engine/common/world.h Normal file
View File

@ -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);

50
engine/gl/gl_draw.h Normal file
View File

@ -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);

139
engine/gl/shader.h Normal file
View File

@ -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);

2087
engine/server/net_preparse.c Normal file

File diff suppressed because it is too large Load Diff

6854
engine/server/pr_cmds.c Normal file

File diff suppressed because it is too large Load Diff

305
engine/server/progdefs.h Normal file
View File

@ -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

115
engine/server/progs.h Normal file
View File

@ -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

315
engine/server/q2game.h Normal file
View File

@ -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

105
engine/server/qwsvdef.h Normal file
View File

@ -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

1119
engine/server/savegame.c Normal file

File diff suppressed because it is too large Load Diff

1060
engine/server/server.h Normal file

File diff suppressed because it is too large Load Diff

1554
engine/server/sv_ccmds.c Normal file

File diff suppressed because it is too large Load Diff

644
engine/server/sv_chat.c Normal file
View File

@ -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