splitscreen cleaned up more.

demo menu can now leave quake dir.
scissor+line rendering abstracted from csqc.
added a rain particle effect to the 'high' particle set.
added support for parsing ezquake's koi stuff. Still only generates utf-8.
implemented some string-buffer builtins from dp that have been stubs for quite some time.
http code now supports/uses gzipped downloads properly.
added support for non-blocking tcp connects.
#pragma optimize makes more sense with the gui version now.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4397 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-06-23 02:17:02 +00:00
parent 10d2188eb2
commit fa9252cefa
121 changed files with 6785 additions and 4637 deletions

View File

@ -34,6 +34,13 @@ WHOAMI:=$(shell whoami)
ifeq ($(FTE_TARGET),win32)
ifeq ($(shell $(CC) -v 2>&1 | grep mingw),)
#CC didn't state that it was mingw... so try fixing that up
ifneq ($(shell which i686-w64-mingw32-gcc 2> /dev/null),)
#yup, the alternative exists (this matches the one debian has)
CC=i686-w64-mingw32-gcc
WINDRES=i686-w64-mingw32-windres
STRIP=i686-w64-mingw32-strip
# BITS?=32
endif
ifneq ($(shell which i586-mingw32msvc-gcc 2> /dev/null),)
#yup, the alternative exists (this matches the one debian has)
CC=i586-mingw32msvc-gcc

View File

@ -35,10 +35,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define BUTTON_ATTACK 1
#define MAX_ANGLE_TURN 10
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
@ -50,11 +46,6 @@ cvar_t cl_selfcam = SCVAR("cl_selfcam", "1");
//cvar_t cl_camera_maxpitch = {"cl_camera_maxpitch", "10" };
//cvar_t cl_camera_maxyaw = {"cl_camera_maxyaw", "30" };
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];
int selfcam=1;
@ -64,11 +55,11 @@ static float vlen(vec3_t v)
}
// returns true if weapon model should be drawn in camera mode
qboolean Cam_DrawViewModel(int pnum)
qboolean Cam_DrawViewModel(playerview_t *pv)
{
if (cl.spectator)
{
if (autocam[pnum] && locked[pnum] && cl_chasecam.ival)
if (pv->cam_auto && pv->cam_locked && cl_chasecam.ival)
return true;
return false;
}
@ -81,60 +72,66 @@ qboolean Cam_DrawViewModel(int pnum)
}
// returns true if we should draw this player, we don't if we are chase camming
qboolean Cam_DrawPlayer(int pnum, int playernum)
qboolean Cam_DrawEntity(playerview_t *pv, int entitykey)
{
// if (!entitykey)
return true;
// if (playernum == cl.playernum[pnum])
// return false;
if (cl.spectator)
{
if (autocam[pnum] && locked[pnum] && (cl_chasecam.value||scr_chatmode==2) &&
spec_track[pnum] == playernum && r_secondaryview != 2)
if (pv->cam_auto && pv->cam_locked && (cl_chasecam.value||scr_chatmode==2) &&
pv->cam_spec_track+1 == entitykey && r_secondaryview != 2)
return false;
}
else
{
if (selfcam == 1 && !r_refdef.externalview)
if (playernum == (cl.viewentity[pnum]?cl.viewentity[pnum]-1:(cl.playernum[pnum])))
if (entitykey == pv->viewentity)
return false;
}
return true;
}
int Cam_TrackNum(int pnum)
int Cam_TrackNum(playerview_t *pv)
{
if (!autocam[pnum])
if (!pv->cam_auto)
return -1;
return spec_track[pnum];
return pv->cam_spec_track;
}
void Cam_Unlock(int pnum)
void Cam_Unlock(playerview_t *pv)
{
if (autocam[pnum])
if (pv->cam_auto)
{
CL_SendClientCommand(true, "ptrack");
autocam[pnum] = CAM_NONE;
locked[pnum] = false;
pv->cam_auto = CAM_NONE;
pv->cam_locked = false;
pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); //free floating
Sbar_Changed();
}
}
void Cam_Lock(int pnum, int playernum)
void Cam_Lock(playerview_t *pv, int playernum)
{
int i;
cam_lastviewtime[pnum] = -1000;
pv->cam_lastviewtime = -1000;
CL_SendClientCommand(true, "ptrack %i", playernum);
spec_track[pnum] = playernum;
locked[pnum] = false;
pv->cam_spec_track = playernum;
pv->cam_locked = false;
pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); //free floating
Skin_FlushPlayers();
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
{
memcpy(&cl.playerview[pnum].stats, cl.players[playernum].stats, sizeof(cl.playerview[pnum].stats));
locked[pnum] = true; //instantly lock if the player is valid.
memcpy(&pv->stats, cl.players[playernum].stats, sizeof(pv->stats));
pv->cam_locked = true; //instantly lock if the player is valid.
pv->viewentity = playernum+1;
}
Sbar_Changed();
@ -218,7 +215,7 @@ static qboolean Cam_IsVisible(vec3_t playerorigin, vec3_t vec)
return true;
}
static qboolean InitFlyby(int pnum, vec3_t selforigin, vec3_t playerorigin, vec3_t playerviewangles, int checkvis)
static qboolean InitFlyby(playerview_t *pv, vec3_t selforigin, vec3_t playerorigin, vec3_t playerviewangles, int checkvis)
{
float f, max;
vec3_t vec, vec2;
@ -317,16 +314,16 @@ static qboolean InitFlyby(int pnum, vec3_t selforigin, vec3_t playerorigin, vec3
return false;
}
locked[pnum] = true;
VectorCopy(vec, desired_position[pnum]);
pv->cam_locked = true;
VectorCopy(vec, pv->cam_desired_position);
return true;
}
static void Cam_CheckHighTarget(int pnum)
static void Cam_CheckHighTarget(playerview_t *pv)
{
int i, j, max;
player_info_t *s;
int sp;
playerview_t *spv;
j = -1;
for (i = 0, max = -9999; i < MAX_CLIENTS; i++)
@ -334,12 +331,13 @@ static void Cam_CheckHighTarget(int pnum)
s = &cl.players[i];
if (s->name[0] && !s->spectator && s->frags > max)
{
for (sp = pnum-1; sp >= 0; sp--)
//skip it if an earlier seat is watching it already
for (spv = pv-1; spv >= cl.playerview && spv < &cl.playerview[cl.splitclients]; spv--)
{
if (Cam_TrackNum(sp) == i)
if (Cam_TrackNum(spv) == i)
break;
}
if (sp == -1)
if (!(spv >= cl.playerview && spv < &cl.playerview[cl.splitclients]))
{
max = s->frags;
j = i;
@ -348,21 +346,22 @@ static void Cam_CheckHighTarget(int pnum)
}
if (j >= 0)
{
if (!locked[pnum] || cl.players[j].frags > cl.players[spec_track[pnum]].frags)
if (!pv->cam_locked || cl.players[j].frags > cl.players[pv->cam_spec_track].frags)
{
Cam_Lock(pnum, j);
for (sp = pnum+1; sp < cl.splitclients; sp++)
Cam_Lock(pv, j);
//un-lock any higher seats watching our new target. this keeps things ordered.
for (spv = pv+1; spv >= cl.playerview && spv < &cl.playerview[cl.splitclients]; spv++)
{
if (Cam_TrackNum(sp) == j)
locked[sp] = false;
if (Cam_TrackNum(spv) == j)
spv->cam_locked = false;
}
}
}
else
Cam_Unlock(pnum);
Cam_Unlock(pv);
}
void Cam_SelfTrack(int pnum)
void Cam_SelfTrack(playerview_t *pv)
{
vec3_t vec;
if (!cl.worldmodel || cl.worldmodel->needload)
@ -378,36 +377,36 @@ void Cam_SelfTrack(int pnum)
vec3_t forward, right, up;
trace_t tr;
AngleVectors(r_refdef.viewangles, forward, right, up);
VectorMA(cl.playerview[pnum].simorg, -128, forward, desired_position[pnum]);
tr = Cam_DoTrace(cl.playerview[pnum].simorg, desired_position[pnum]);
VectorCopy(tr.endpos, desired_position[pnum]);
VectorMA(pv->simorg, -128, forward, pv->cam_desired_position);
tr = Cam_DoTrace(pv->simorg, pv->cam_desired_position);
VectorCopy(tr.endpos, pv->cam_desired_position);
}
else
{ //view from a random wall
if (!locked[pnum] || !Cam_IsVisible(cl.playerview[pnum].simorg, desired_position[pnum]))
if (!pv->cam_locked || !Cam_IsVisible(pv->simorg, pv->cam_desired_position))
{
if (!locked[pnum] || realtime - cam_lastviewtime[pnum] > 0.1)
if (!pv->cam_locked || realtime - pv->cam_lastviewtime > 0.1)
{
if (!InitFlyby(pnum, desired_position[pnum], cl.playerview[pnum].simorg, cl.playerview[pnum].simangles, true))
InitFlyby(pnum, desired_position[pnum], cl.playerview[pnum].simorg, cl.playerview[pnum].simangles, false);
cam_lastviewtime[pnum] = realtime;
if (!InitFlyby(pv, pv->cam_desired_position, pv->simorg, pv->simangles, true))
InitFlyby(pv, pv->cam_desired_position, pv->simorg, pv->simangles, false);
pv->cam_lastviewtime = realtime;
}
}
else
{
cam_lastviewtime[pnum] = realtime;
pv->cam_lastviewtime = realtime;
}
//tracking failed.
if (!locked[pnum])
if (!pv->cam_locked)
return;
}
// move there locally immediately
VectorCopy(desired_position[pnum], r_refdef.vieworg);
VectorCopy(pv->cam_desired_position, r_refdef.vieworg);
VectorSubtract(cl.playerview[pnum].simorg, desired_position[pnum], vec);
VectorSubtract(pv->simorg, pv->cam_desired_position, vec);
VectorAngles(vec, NULL, r_refdef.viewangles);
r_refdef.viewangles[0] = -r_refdef.viewangles[0];
}
@ -417,7 +416,7 @@ void Cam_SelfTrack(int pnum)
//
// 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)
void Cam_Track(playerview_t *pv, usercmd_t *cmd)
{
player_state_t *player, *self;
inframe_t *frame;
@ -427,51 +426,51 @@ void Cam_Track(int pnum, usercmd_t *cmd)
if (!cl.spectator || !cl.worldmodel) //can happen when the server changes level
return;
if (cl_hightrack.value && !locked[pnum])
Cam_CheckHighTarget(pnum);
if (cl_hightrack.value && !pv->cam_locked)
Cam_CheckHighTarget(pv);
if (!autocam[pnum] || cls.state != ca_active)
if (!pv->cam_auto || cls.state != ca_active)
return;
if (locked[pnum] && (!cl.players[spec_track[pnum]].name[0] || cl.players[spec_track[pnum]].spectator))
if (pv->cam_locked && (!cl.players[pv->cam_spec_track].name[0] || cl.players[pv->cam_spec_track].spectator))
{
locked[pnum] = false;
pv->cam_locked = false;
if (cl_hightrack.value)
Cam_CheckHighTarget(pnum);
Cam_CheckHighTarget(pv);
else
Cam_Unlock(pnum);
Cam_Unlock(pv);
return;
}
frame = &cl.inframes[cl.validsequence & UPDATE_MASK];
player = frame->playerstate + spec_track[pnum];
self = frame->playerstate + cl.playernum[pnum];
player = frame->playerstate + pv->cam_spec_track;
self = frame->playerstate + pv->playernum;
if (!locked[pnum] || !Cam_IsVisible(player->origin, desired_position[pnum]))
if (!pv->cam_locked || !Cam_IsVisible(player->origin, pv->cam_desired_position))
{
if (!locked[pnum] || realtime - cam_lastviewtime[pnum] > 0.1)
if (!pv->cam_locked || realtime - pv->cam_lastviewtime > 0.1)
{
if (!InitFlyby(pnum, self->origin, player->origin, player->viewangles, true))
InitFlyby(pnum, self->origin, player->origin, player->viewangles, false);
cam_lastviewtime[pnum] = realtime;
if (!InitFlyby(pv, self->origin, player->origin, player->viewangles, true))
InitFlyby(pv, self->origin, player->origin, player->viewangles, false);
pv->cam_lastviewtime = realtime;
}
}
else
{
cam_lastviewtime[pnum] = realtime;
pv->cam_lastviewtime = realtime;
}
//tracking failed.
if (!locked[pnum] || !autocam[pnum])
if (!pv->cam_locked || !pv->cam_auto)
return;
if (cl_chasecam.value || scr_chatmode == 2)
{
if (scr_chatmode != 2)
cam_lastviewtime[pnum] = realtime;
pv->cam_lastviewtime = realtime;
VectorCopy(player->viewangles, cl.playerview[pnum].viewangles);
VectorCopy(player->viewangles, pv->viewangles);
if (memcmp(player->origin, &self->origin, sizeof(player->origin)) != 0)
{
if (!cls.demoplayback)
@ -491,23 +490,23 @@ void Cam_Track(int pnum, usercmd_t *cmd)
// Ok, move to our desired position and set our angles to view
// the player
VectorSubtract(desired_position[pnum], self->origin, vec);
VectorSubtract(pv->cam_desired_position, 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]);
MSG_WriteCoord (&cls.netchan.message, pv->cam_desired_position[0]);
MSG_WriteCoord (&cls.netchan.message, pv->cam_desired_position[1]);
MSG_WriteCoord (&cls.netchan.message, pv->cam_desired_position[2]);
}
// move there locally immediately
VectorCopy(desired_position[pnum], self->origin);
VectorCopy(pv->cam_desired_position, self->origin);
VectorSubtract(player->origin, desired_position[pnum], vec);
VectorAngles(vec, NULL, cl.playerview[pnum].viewangles);
cl.playerview[pnum].viewangles[0] = -cl.playerview[pnum].viewangles[0];
VectorSubtract(player->origin, pv->cam_desired_position, vec);
VectorAngles(vec, NULL, pv->viewangles);
pv->viewangles[0] = -pv->viewangles[0];
}
void Cam_SetAutoTrack(int userid)
@ -515,7 +514,7 @@ void Cam_SetAutoTrack(int userid)
}
void Cam_TrackCrosshairedPlayer(int pnum)
void Cam_TrackCrosshairedPlayer(playerview_t *pv)
{
inframe_t *frame;
player_state_t *player;
@ -526,7 +525,7 @@ void Cam_TrackCrosshairedPlayer(int pnum)
vec3_t dir;
frame = &cl.inframes[cl.validsequence & UPDATE_MASK];
player = frame->playerstate + cl.playernum[pnum];
player = frame->playerstate + pv->playernum;
VectorCopy(player->origin, selforg);
for (i = 0; i < MAX_CLIENTS; i++)
@ -544,12 +543,12 @@ void Cam_TrackCrosshairedPlayer(int pnum)
Con_Printf("Track %i? %f\n", best, bestdot);
if (best != -1) //did we actually get someone?
{
autocam[pnum]++;
Cam_Lock(pnum, best);
pv->cam_auto++;
Cam_Lock(pv, best);
}
}
void Cam_FinishMove(int pnum, usercmd_t *cmd)
void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
{
int i;
player_info_t *s;
@ -571,26 +570,26 @@ void Cam_FinishMove(int pnum, usercmd_t *cmd)
nb |= (cmd->forwardmove>0)?32:0;
nb |= (cmd->upmove<0)?64:0;
nb |= (cmd->upmove>0)?128:0;
if (Cam_TrackNum(pnum) >= 0)
if (Cam_TrackNum(pv) >= 0)
{
if (nb & (nb ^ oldbuttons[pnum]) & 4)
if (nb & (nb ^ pv->cam_oldbuttons) & 4)
Cvar_SetValue(&cl_demospeed, max(cl_demospeed.value - 0.1, 0));
if (nb & (nb ^ oldbuttons[pnum]) & 8)
if (nb & (nb ^ pv->cam_oldbuttons) & 8)
Cvar_SetValue(&cl_demospeed, min(cl_demospeed.value + 0.1, 10));
if (nb & (nb ^ oldbuttons[pnum]) & (4|8))
if (nb & (nb ^ pv->cam_oldbuttons) & (4|8))
Con_Printf("playback speed: %g%%\n", cl_demospeed.value*100);
if (nb & (nb ^ oldbuttons[pnum]) & 16)
if (nb & (nb ^ pv->cam_oldbuttons) & 16)
Cbuf_AddText("demo_jump +10", RESTRICT_LOCAL);
if (nb & (nb ^ oldbuttons[pnum]) & 32)
if (nb & (nb ^ pv->cam_oldbuttons) & 32)
Cbuf_AddText("demo_jump -10", RESTRICT_LOCAL);
if (nb & (nb ^ oldbuttons[pnum]) & (4|8))
if (nb & (nb ^ pv->cam_oldbuttons) & (4|8))
Con_Printf("playback speed: %g%%\n", cl_demospeed.value*100);
if (nb & (nb ^ oldbuttons[pnum]) & 64)
if (nb & (nb ^ pv->cam_oldbuttons) & 64)
Cvar_SetValue(&cl_splitscreen, max(cl_splitscreen.ival - 1, 0));
if (nb & (nb ^ oldbuttons[pnum]) & 128)
if (nb & (nb ^ pv->cam_oldbuttons) & 128)
Cvar_SetValue(&cl_splitscreen, min(cl_splitscreen.ival + 1, MAX_SPLITS-1));
}
oldbuttons[pnum] = (oldbuttons[pnum] & 3) | (nb & ~3);
pv->cam_oldbuttons = (pv->cam_oldbuttons & 3) | (nb & ~3);
if (cmd->impulse)
{
int pl = cmd->impulse;
@ -609,11 +608,12 @@ void Cam_FinishMove(int pnum, usercmd_t *cmd)
pl--;
if (!pl)
{
Cam_Lock(pnum, i);
pnum++;
if (pnum < cl.splitclients)
Cam_Lock(pv, i);
if (pv >= &cl.playerview[0] && pv < &cl.playerview[cl.splitclients])
{
pl = 1;
pv++;
}
else
break;
}
@ -625,16 +625,15 @@ void Cam_FinishMove(int pnum, usercmd_t *cmd)
if (cmd->buttons & BUTTON_ATTACK)
{
if (!(oldbuttons[pnum] & BUTTON_ATTACK))
if (!(pv->cam_oldbuttons & BUTTON_ATTACK))
{
pv->cam_oldbuttons |= BUTTON_ATTACK;
pv->cam_auto++;
oldbuttons[pnum] |= BUTTON_ATTACK;
autocam[pnum]++;
if (autocam[pnum] > CAM_TRACK)
if (pv->cam_auto > CAM_TRACK)
{
Cam_Unlock(pnum);
VectorCopy(cl.playerview[pnum].viewangles, cmd->angles);
Cam_Unlock(pv);
VectorCopy(pv->viewangles, cmd->angles);
return;
}
}
@ -643,62 +642,62 @@ void Cam_FinishMove(int pnum, usercmd_t *cmd)
}
else
{
oldbuttons[pnum] &= ~BUTTON_ATTACK;
if (!autocam[pnum])
pv->cam_oldbuttons &= ~BUTTON_ATTACK;
if (!pv->cam_auto)
{
if ((cmd->buttons & BUTTON_JUMP) && !(oldbuttons[pnum] & BUTTON_JUMP))
Cam_TrackCrosshairedPlayer(pnum);
oldbuttons[pnum] = (oldbuttons[pnum]&~BUTTON_JUMP) | (cmd->buttons & BUTTON_JUMP);
if ((cmd->buttons & BUTTON_JUMP) && !(pv->cam_oldbuttons & BUTTON_JUMP))
Cam_TrackCrosshairedPlayer(pv);
pv->cam_oldbuttons = (pv->cam_oldbuttons&~BUTTON_JUMP) | (cmd->buttons & BUTTON_JUMP);
return;
}
}
if (autocam[pnum] && cl_hightrack.ival)
if (pv->cam_auto && cl_hightrack.ival)
{
Cam_CheckHighTarget(pnum);
Cam_CheckHighTarget(pv);
return;
}
if (locked[pnum])
if (pv->cam_locked)
{
if ((cmd->buttons & BUTTON_JUMP) && (oldbuttons[pnum] & BUTTON_JUMP))
if ((cmd->buttons & BUTTON_JUMP) && (pv->cam_oldbuttons & BUTTON_JUMP))
return; // don't pogo stick
if (!(cmd->buttons & BUTTON_JUMP))
{
oldbuttons[pnum] &= ~BUTTON_JUMP;
pv->cam_oldbuttons &= ~BUTTON_JUMP;
return;
}
oldbuttons[pnum] |= BUTTON_JUMP; // don't jump again until released
pv->cam_oldbuttons |= 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;
if (pv->cam_locked && pv->cam_auto)
end = (pv->cam_spec_track + 1) % MAX_CLIENTS;
else
end = spec_track[pnum];
end = pv->cam_spec_track;
i = end;
do
{
s = &cl.players[i];
if (s->name[0] && !s->spectator)
{
Cam_Lock(pnum, i);
Cam_Lock(pv, i);
return;
}
i = (i + 1) % MAX_CLIENTS;
} while (i != end);
// stay on same guy?
i = spec_track[pnum];
i = pv->cam_spec_track;
s = &cl.players[i];
if (s->name[0] && !s->spectator)
{
Cam_Lock(pnum, i);
Cam_Lock(pv, i);
return;
}
Con_Printf("No target found ...\n");
autocam[pnum] = locked[pnum] = false;
pv->cam_auto = pv->cam_locked = false;
}
void Cam_Reset(void)
@ -706,21 +705,20 @@ void Cam_Reset(void)
int pnum;
for (pnum = 0; pnum < MAX_SPLITS; pnum++)
{
autocam[pnum] = CAM_NONE;
spec_track[pnum] = 0;
playerview_t *pv = &cl.playerview[pnum];
pv->cam_auto = CAM_NONE;
pv->cam_spec_track = 0;
}
}
void Cam_TrackPlayer(int pnum, char *cmdname, char *plrarg)
void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg)
{
playerview_t *pv = &cl.playerview[seat];
int slot;
player_info_t *s;
if (pnum >= MAX_SPLITS)
{
Con_Printf("This command is unavailable in this compilation.\n");
if (seat >= MAX_SPLITS)
return;
}
if (cls.state <= ca_connected)
{
@ -736,7 +734,7 @@ void Cam_TrackPlayer(int pnum, char *cmdname, char *plrarg)
if (!Q_strcasecmp(plrarg, "off"))
{
Cam_Unlock(pnum);
Cam_Unlock(pv);
return;
}
@ -782,9 +780,9 @@ void Cam_TrackPlayer(int pnum, char *cmdname, char *plrarg)
}
}
autocam[pnum] = CAM_TRACK;
Cam_Lock(pnum, slot);
locked[pnum] = true;
pv->cam_auto = CAM_TRACK;
Cam_Lock(pv, slot);
pv->cam_locked = true;
}
void Cam_Track_f(void)

View File

@ -19,11 +19,6 @@ void CG_Command_f(void);
#define CGTAGNUM 5423
#define VM_TOSTRCACHE(a) VMQ3_StringToHandle(VM_POINTER(a))
#define VM_FROMSTRCACHE(a) VMQ3_StringFromHandle(a)
char *VMQ3_StringFromHandle(int handle);
int VMQ3_StringToHandle(char *str);
extern model_t mod_known[];
extern int mod_numknown;
#define VM_FROMMHANDLE(a) ((a&&((unsigned int)a)<=mod_numknown)?mod_known+a-1:NULL)
@ -331,10 +326,10 @@ qboolean CGQ3_GetUserCmd(int cmdNumber, q3usercmd_t *ucmd)
usercmd_t *cmd;
cmdNumber--;
if (cmdNumber > ccs.currentUserCmdNumber)
if (cmdNumber > cl.movesequence)
Host_EndGame("CL_GetUserCmd: cmdNumber > ccs.currentUserCmdNumber");
if (ccs.currentUserCmdNumber - cmdNumber > CMD_MASK)
if (cl.movesequence - cmdNumber > CMD_MASK)
return false; // too old
cmd = &cl.outframes[(cmdNumber) & CMD_MASK].cmd[0];
@ -929,7 +924,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
break;
case CG_GETCURRENTCMDNUMBER:
VM_LONG(ret) = ccs.currentUserCmdNumber;
VM_LONG(ret) = cl.movesequence;
break;
case CG_GETUSERCMD:
VALIDATEPOINTER(arg[1], sizeof(q3usercmd_t));
@ -1140,7 +1135,7 @@ void CG_Start (void)
if (cgvm)
{ //hu... cgame doesn't appear to have a query version call!
SCR_EndLoadingPlaque();
VM_Call(cgvm, CG_INIT, ccs.serverMessageNum, ccs.lastServerCommandNum, cl.playernum[0]);
VM_Call(cgvm, CG_INIT, ccs.serverMessageNum, ccs.lastServerCommandNum, cl.playerview[0].playernum);
}
else
{

View File

@ -134,6 +134,7 @@ Dumps the current net message, prefixed by the length and view angles
void CL_WriteDemoMessage (sizebuf_t *msg)
{
int len;
int i;
float fl;
qbyte c;
@ -148,9 +149,27 @@ void CL_WriteDemoMessage (sizebuf_t *msg)
c = dem_read;
VFS_WRITE (cls.demooutfile, &c, sizeof(c));
len = LittleLong (msg->cursize);
VFS_WRITE (cls.demooutfile, &len, 4);
VFS_WRITE (cls.demooutfile, msg->data, msg->cursize);
if (*(int*)msg->data == -1)
{
//connectionless packet.
len = LittleLong (msg->cursize);
VFS_WRITE (cls.demooutfile, &len, 4);
VFS_WRITE (cls.demooutfile, msg->data + msg_readcount, msg->cursize - msg_readcount);
}
else
{
//regenerate a legacy netchan. no fragmentation support, but whatever. this ain't udp.
//the length
len = LittleLong (msg->cursize - msg_readcount + 8);
VFS_WRITE (cls.demooutfile, &len, 4);
//hack the netchan here.
i = cls.netchan.incoming_sequence;
VFS_WRITE (cls.demooutfile, &i, 4);
i = cls.netchan.incoming_acknowledged;
VFS_WRITE (cls.demooutfile, &i, 4);
//and the data
VFS_WRITE (cls.demooutfile, msg->data + msg_readcount, msg->cursize - msg_readcount);
}
VFS_FLUSH (cls.demooutfile);
}
@ -729,23 +748,34 @@ readit:
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
{
int seat;
switch(cls_lasttype)
{
case dem_multiple:
tracknum = spec_track[0];
if (!autocam[0])
tracknum = -1;
if (tracknum == -1 || !(cls_lastto & (1 << tracknum)))
for (seat = 0; seat < cl.splitclients; seat++)
{
tracknum = cl.playerview[seat].cam_spec_track;
if (!cl.playerview[seat].cam_auto)
tracknum = -1;
if (tracknum == -1 || !(cls_lastto & (1 << tracknum)))
continue;
}
if (seat == cl.splitclients)
{
olddemotime = demotime;
goto readnext;
}
break;
case dem_single:
tracknum = spec_track[0];
if (!autocam[0])
tracknum = -1;
if (tracknum == -1 || cls_lastto != tracknum)
for (seat = 0; seat < cl.splitclients; seat++)
{
tracknum = cl.playerview[seat].cam_spec_track;
if (!cl.playerview[seat].cam_auto)
tracknum = -1;
if (tracknum == -1 || !(cls_lastto != tracknum))
continue;
}
if (seat == cl.splitclients)
{
olddemotime = demotime;
goto readnext;
@ -834,8 +864,6 @@ qboolean CL_GetMessage (void)
if (NET_GetPacket (NS_CLIENT, 0) < 0)
return false;
CL_WriteDemoMessage (&net_message);
return true;
}
@ -1107,15 +1135,27 @@ void CL_Record_f (void)
MSG_WriteLong (&buf, cl.servercount);
MSG_WriteString (&buf, gamedirfile);
for (i = 0; i < cl.splitclients; i++)
if (cls.fteprotocolextensions2 & PEXT2_MAXPLAYERS)
{
if (cl.spectator)
MSG_WriteByte (&buf, cl.playernum[i] | 128);
else
MSG_WriteByte (&buf, cl.playernum[i]);
MSG_WriteByte (&buf, cl.allocated_client_slots);
MSG_WriteByte (&buf, cl.splitclients | (cl.spectator?128:0));
for (i = 0; i < cl.splitclients; i++)
{
MSG_WriteByte (&buf, cl.playerview[i].playernum);
}
}
else
{
for (i = 0; i < cl.splitclients; i++)
{
if (cl.spectator)
MSG_WriteByte (&buf, cl.playerview[i].playernum | 128);
else
MSG_WriteByte (&buf, cl.playerview[i].playernum);
}
if (cls.fteprotocolextensions & PEXT_SPLITSCREEN)
MSG_WriteByte (&buf, 128);
}
if (cls.fteprotocolextensions & PEXT_SPLITSCREEN)
MSG_WriteByte (&buf, 128);
// send full levelname
MSG_WriteString (&buf, cl.levelname);
@ -1141,10 +1181,10 @@ void CL_Record_f (void)
MSG_WriteByte (&buf, 0); // none in demos
#ifdef PEXT_SETVIEW
if (cl.viewentity[0]) //tell the player if we have a different view entity
if (cl.playerview[0].viewentity != cl.playerview[0].playernum+1) //tell the player if we have a different view entity
{
MSG_WriteByte (&buf, svc_setview);
MSG_WriteByte (&buf, cl.viewentity[0]);
MSG_WriteEntity (&buf, cl.playerview[0].viewentity);
}
#endif
// flush packet
@ -1284,30 +1324,45 @@ void CL_Record_f (void)
// send current status of all other players
for (i = 0; i < MAX_CLIENTS; i++)
for (i = 0; i < cl.allocated_client_slots; i++)
{
player = cl.players + i;
MSG_WriteByte (&buf, svc_updatefrags);
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, player->frags);
if (player->frags != 0)
{
MSG_WriteByte (&buf, svc_updatefrags);
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, player->frags);
}
MSG_WriteByte (&buf, svc_updateping);
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, player->ping);
if (player->ping != 0)
{
MSG_WriteByte (&buf, svc_updateping);
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, player->ping);
}
MSG_WriteByte (&buf, svc_updatepl);
MSG_WriteByte (&buf, i);
MSG_WriteByte (&buf, player->pl);
if (player->pl != 0)
{
MSG_WriteByte (&buf, svc_updatepl);
MSG_WriteByte (&buf, i);
MSG_WriteByte (&buf, player->pl);
}
MSG_WriteByte (&buf, svc_updateentertime);
MSG_WriteByte (&buf, i);
MSG_WriteFloat (&buf, player->entertime);
if (*player->userinfo)
{
MSG_WriteByte (&buf, svc_updateentertime);
MSG_WriteByte (&buf, i);
MSG_WriteFloat (&buf, player->entertime);
}
MSG_WriteByte (&buf, svc_updateuserinfo);
MSG_WriteByte (&buf, i);
MSG_WriteLong (&buf, player->userid);
MSG_WriteString (&buf, player->userinfo);
if (*player->userinfo)
{
MSG_WriteByte (&buf, svc_updateuserinfo);
MSG_WriteByte (&buf, i);
MSG_WriteLong (&buf, player->userid);
MSG_WriteString (&buf, player->userinfo);
}
if (buf.cursize > MAX_QWMSGLEN/2)
{
@ -1443,6 +1498,7 @@ play [demoname]
*/
void CL_PlayDemo_f (void)
{
char *demoname;
if (Cmd_Argc() != 2)
{
Con_Printf ("playdemo <demoname> : plays a demo\n");
@ -1463,7 +1519,10 @@ void CL_PlayDemo_f (void)
#endif
#endif
CL_PlayDemo(Cmd_Argv(1));
demoname = Cmd_Argv(1);
if (*demoname == '#' && Cmd_FromGamecode())
return;
CL_PlayDemo(demoname);
}
void CL_PlayDemo(char *demoname)

View File

@ -233,9 +233,10 @@ void CL_DecayLights (void)
{
int i;
dlight_t *dl;
float frametime = host_frametime;
if (cl.paused) //DON'T DO IT!!!
return;
frametime = 0;
dl = cl_dlights+rtlights_first;
for (i=rtlights_first ; i<RTL_FIRST ; i++, dl++)
@ -258,7 +259,7 @@ void CL_DecayLights (void)
continue;
}
dl->radius -= host_frametime*dl->decay;
dl->radius -= frametime*dl->decay;
if (dl->radius < 0)
{
if (i==rtlights_first)
@ -269,21 +270,21 @@ void CL_DecayLights (void)
if (dl->channelfade[0])
{
dl->color[0] -= host_frametime*dl->channelfade[0];
dl->color[0] -= frametime*dl->channelfade[0];
if (dl->color[0] < 0)
dl->color[0] = 0;
}
if (dl->channelfade[1])
{
dl->color[1] -= host_frametime*dl->channelfade[1];
dl->color[1] -= frametime*dl->channelfade[1];
if (dl->color[1] < 0)
dl->color[1] = 0;
}
if (dl->channelfade[2])
{
dl->color[2] -= host_frametime*dl->channelfade[2];
dl->color[2] -= frametime*dl->channelfade[2];
if (dl->color[2] < 0)
dl->color[2] = 0;
}
@ -1614,9 +1615,9 @@ void CL_RotateAroundTag(entity_t *ent, int entnum, int parenttagent, int parentt
{
extern int parsecountmod;
// Con_Printf("tagent %i\n", tagent);
if (parenttagent <= MAX_CLIENTS && parenttagent > 0)
if (parenttagent <= cl.allocated_client_slots && parenttagent > 0)
{
if (parenttagent == cl.playernum[0]+1)
if (parenttagent == cl.playerview[0].playernum+1)
{
org = cl.playerview[0].simorg;
ang = cl.playerview[0].simangles;
@ -3221,7 +3222,6 @@ void CL_LinkPacketEntities (void)
cl_numvisedicts++;
ent->externalmodelview = 0;
ent->forcedshader = NULL;
ent->keynum = state->number;
@ -3234,7 +3234,7 @@ void CL_LinkPacketEntities (void)
ent->flags = 0;
if (state->dpflags & RENDER_VIEWMODEL)
ent->flags |= Q2RF_WEAPONMODEL|Q2RF_MINLIGHT|Q2RF_DEPTHHACK;
if (state->dpflags & RENDER_EXTERIORMODEL)
if ((state->dpflags & RENDER_EXTERIORMODEL) || r_refdef.playerview->viewentity == state->number)
ent->flags |= Q2RF_EXTERNALMODEL;
if (state->effects & NQEF_ADDITIVE)
ent->flags |= Q2RF_ADDITIVE;
@ -3245,10 +3245,6 @@ void CL_LinkPacketEntities (void)
if (state->trans != 0xff)
ent->flags |= Q2RF_TRANSLUCENT;
/*FIXME: pay attention to tags instead, so nexuiz can work with splitscreen*/
if (ent->flags & Q2RF_EXTERNALMODEL)
ent->externalmodelview = ~0;
/* if (le->origin[2] < r_refdef.waterheight != le->lastorigin[2] < r_refdef.waterheight)
{
P_RunParticleEffectTypeString(le->origin, NULL, 1, "te_watertransition");
@ -3316,7 +3312,7 @@ void CL_LinkPacketEntities (void)
/*if this entity is in a player's slot...*/
if (ent->keynum <= cl.allocated_client_slots)
{
if (!cl.nolocalplayer[0])
if (!cl.playerview[0].nolocalplayer)
ent->keynum += MAX_EDICTS;
}
@ -3657,10 +3653,8 @@ void CL_ParsePlayerinfo (void)
if (cls.findtrack && info->stats[STAT_HEALTH] > 0)
{
// extern int ideal_track;
autocam[0] = CAM_TRACK;
Cam_Lock(0, num);
// ideal_track = num;
cl.playerview[0].cam_auto = CAM_TRACK;
Cam_Lock(&cl.playerview[0], num);
cls.findtrack = false;
}
@ -3730,28 +3724,33 @@ void CL_ParsePlayerinfo (void)
cl.players[num].statsf[STAT_WEAPONFRAME] = state->weaponframe;
for (i = 0; i < cl.splitclients; i++)
{
if (spec_track[i] == num)
playerview_t *pv = &cl.playerview[i];
if (pv->cam_spec_track == num)
{
cl.playerview[i].stats[STAT_WEAPONFRAME] = state->weaponframe;
cl.playerview[i].statsf[STAT_WEAPONFRAME] = state->weaponframe;
pv->stats[STAT_WEAPONFRAME] = state->weaponframe;
pv->statsf[STAT_WEAPONFRAME] = state->weaponframe;
}
}
//add a new splitscreen autotrack view if we can
if (cl.splitclients < MAX_SPLITS && !cl.players[num].spectator)
{
extern cvar_t cl_splitscreen;
if (cl.splitclients < cl_splitscreen.value+1)
{
for (i = 0; i < cl.splitclients; i++)
if (autocam[i] && spec_track[i] == num)
{
playerview_t *pv = &cl.playerview[i];
if (pv->cam_auto && pv->cam_spec_track == num)
return;
}
if (i == cl.splitclients)
{
autocam[cl.splitclients] = CAM_TRACK;
spec_track[cl.splitclients] = num;
cl.splitclients++;
Cam_Lock(i, num);
playerview_t *pv = &cl.playerview[cl.splitclients++];
pv->cam_auto = CAM_TRACK;
pv->cam_spec_track = num;
Cam_Lock(pv, num);
}
}
}
@ -3959,10 +3958,11 @@ guess_pm_type:
//can't CL_SetStatInt as we don't know if its actually us or not
for (i = 0; i < cl.splitclients; i++)
{
if ((cl.spectator?spec_track[i]:cl.playernum[i]) == num)
playerview_t *pv = &cl.playerview[i];
if ((cl.spectator?pv->cam_spec_track:pv->playernum) == num)
{
cl.playerview[i].stats[STAT_WEAPONFRAME] = state->weaponframe;
cl.playerview[i].statsf[STAT_WEAPONFRAME] = state->weaponframe;
pv->stats[STAT_WEAPONFRAME] = state->weaponframe;
pv->statsf[STAT_WEAPONFRAME] = state->weaponframe;
}
}
@ -4048,6 +4048,8 @@ void CL_AddFlagModels (entity_t *ent, int team)
newent = CL_NewTempEntity ();
newent->model = cl.model_precache[cl_flagindex];
newent->skinnum = team;
newent->keynum = ent->keynum;
newent->flags |= ent->flags;
AngleVectors (ent->angles, v_forward, v_right, v_up);
v_forward[2] = -v_forward[2]; // reverse z component
@ -4073,6 +4075,7 @@ void CL_AddVWeapModel(entity_t *player, model_t *model)
newent = CL_NewTempEntity ();
newent->keynum = player->keynum;
newent->flags |= player->flags;
VectorCopy(player->origin, newent->origin);
VectorCopy(player->angles, newent->angles);
@ -4165,7 +4168,7 @@ void CL_LinkPlayers (void)
}
// spawn light flashes, even ones coming from invisible objects
if (r_powerupglow.value && !(r_powerupglow.value == 2 && j == cl.playernum[0])
if (r_powerupglow.value && !(r_powerupglow.value == 2 && j == cl.playerview[0].playernum)
&& (state->effects & (EF_BLUE|EF_RED|EF_BRIGHTLIGHT|EF_DIMLIGHT)))
{
vec3_t colour;
@ -4210,7 +4213,7 @@ void CL_LinkPlayers (void)
VectorCopy(state->origin, org);
//make the light appear at the predicted position rather than anywhere else.
for (pnum = 0; pnum < cl.splitclients; pnum++)
if (cl.playernum[pnum] == j)
if (cl.playerview[pnum].playernum == j)
VectorCopy(cl.playerview[pnum].simorg, org);
if (model)
{
@ -4280,29 +4283,25 @@ void CL_LinkPlayers (void)
angles[ROLL] = 0;
angles[ROLL] = V_CalcRoll (angles, state->velocity)*4;
ent->externalmodelview = 0;
if (j+1 == r_refdef.playerview->viewentity || (cl.spectator && r_refdef.playerview->cam_locked && r_refdef.playerview->cam_spec_track == j))
ent->flags |= Q2RF_EXTERNALMODEL;
// the player object gets added with flags | 2
for (pnum = 0; pnum < cl.splitclients; pnum++)
{
if (j == (cl.viewentity[pnum]?cl.viewentity[pnum]:cl.playernum[pnum]))
{
ent->flags |= Q2RF_EXTERNALMODEL;
ent->externalmodelview |= (1<<pnum);
}
if (j == cl.playernum[pnum])
playerview_t *pv = &cl.playerview[pnum];
if (j == pv->playernum)
{
/* if (cl.spectator)
{
cl_numvisedicts--;
continue;
}
*/ angles[0] = -1*cl.playerview[pnum].viewangles[0] / 3;
angles[1] = cl.playerview[pnum].viewangles[1];
angles[2] = cl.playerview[pnum].viewangles[2];
ent->origin[0] = cl.playerview[pnum].simorg[0];
ent->origin[1] = cl.playerview[pnum].simorg[1];
ent->origin[2] = cl.playerview[pnum].simorg[2]+cl.crouch[pnum];
break;
*/ angles[0] = -1*pv->viewangles[0] / 3;
angles[1] = pv->viewangles[1];
angles[2] = pv->viewangles[2];
ent->origin[0] = pv->simorg[0];
ent->origin[1] = pv->simorg[1];
ent->origin[2] = pv->simorg[2]+pv->crouch;
}
}
@ -4380,12 +4379,8 @@ void CL_LinkViewModel(void)
unsigned int plnum;
player_state_t *plstate;
static struct model_s *oldmodel[MAX_SPLITS];
static float lerptime[MAX_SPLITS];
static float frameduration[MAX_SPLITS];
static int prevframe[MAX_SPLITS];
static int oldframe[MAX_SPLITS];
float alpha;
playerview_t *pv = r_refdef.playerview;
extern cvar_t cl_gunx, cl_guny, cl_gunz;
extern cvar_t cl_gunanglex, cl_gunangley, cl_gunanglez;
@ -4396,7 +4391,7 @@ void CL_LinkViewModel(void)
return;
#endif
if (r_drawviewmodel.value <= 0 || !Cam_DrawViewModel(r_refdef.currentplayernum))
if (r_drawviewmodel.value <= 0 || !Cam_DrawViewModel(r_refdef.playerview))
return;
#ifdef Q2CLIENT
@ -4407,10 +4402,10 @@ void CL_LinkViewModel(void)
if (!r_drawentities.ival)
return;
if ((cl.playerview[r_refdef.currentplayernum].stats[STAT_ITEMS] & IT_INVISIBILITY) && r_drawviewmodelinvis.value <= 0)
if ((r_refdef.playerview->stats[STAT_ITEMS] & IT_INVISIBILITY) && r_drawviewmodelinvis.value <= 0)
return;
if (cl.playerview[r_refdef.currentplayernum].stats[STAT_HEALTH] <= 0)
if (r_refdef.playerview->stats[STAT_HEALTH] <= 0)
return;
if (r_drawviewmodel.value > 0 && r_drawviewmodel.value < 1)
@ -4418,7 +4413,7 @@ void CL_LinkViewModel(void)
else
alpha = 1;
if ((cl.playerview[r_refdef.currentplayernum].stats[STAT_ITEMS] & IT_INVISIBILITY)
if ((r_refdef.playerview->stats[STAT_ITEMS] & IT_INVISIBILITY)
&& r_drawviewmodelinvis.value > 0
&& r_drawviewmodelinvis.value < 1)
alpha *= r_drawviewmodelinvis.value;
@ -4428,7 +4423,7 @@ void CL_LinkViewModel(void)
V_ClearEntity(&ent);
ent.model = cl.viewent[r_refdef.currentplayernum].model;
ent.model = r_refdef.playerview->viewent.model;
if (!ent.model)
return;
@ -4457,30 +4452,30 @@ void CL_LinkViewModel(void)
if (!CLHL_AnimateViewEntity(&ent))
#endif
{
ent.framestate.g[FS_REG].frame[0] = cl.viewent[r_refdef.currentplayernum].framestate.g[FS_REG].frame[0];
ent.framestate.g[FS_REG].frame[1] = oldframe[r_refdef.currentplayernum];
ent.framestate.g[FS_REG].frame[0] = pv->viewent.framestate.g[FS_REG].frame[0];
ent.framestate.g[FS_REG].frame[1] = pv->oldframe;
if (ent.framestate.g[FS_REG].frame[0] != prevframe[r_refdef.currentplayernum])
if (ent.framestate.g[FS_REG].frame[0] != pv->prevframe)
{
oldframe[r_refdef.currentplayernum] = ent.framestate.g[FS_REG].frame[1] = prevframe[r_refdef.currentplayernum];
pv->oldframe = ent.framestate.g[FS_REG].frame[1] = pv->prevframe;
frameduration[r_refdef.currentplayernum] = (realtime - lerptime[r_refdef.currentplayernum]);
if (frameduration[r_refdef.currentplayernum] < 0.01)//no faster than 100 times a second... to avoid divide by zero
frameduration[r_refdef.currentplayernum] = 0.01;
if (frameduration[r_refdef.currentplayernum] > 0.2) //no slower than 5 times a second
frameduration[r_refdef.currentplayernum] = 0.2;
lerptime[r_refdef.currentplayernum] = realtime;
pv->frameduration = (realtime - pv->lerptime);
if (pv->frameduration < 0.01)//no faster than 100 times a second... to avoid divide by zero
pv->frameduration = 0.01;
if (pv->frameduration > 0.2) //no slower than 5 times a second
pv->frameduration = 0.2;
pv->lerptime = realtime;
}
prevframe[r_refdef.currentplayernum] = ent.framestate.g[FS_REG].frame[0];
pv->prevframe = ent.framestate.g[FS_REG].frame[0];
if (ent.model != oldmodel[r_refdef.currentplayernum])
if (ent.model != pv->oldmodel)
{
oldmodel[r_refdef.currentplayernum] = ent.model;
oldframe[r_refdef.currentplayernum] = ent.framestate.g[FS_REG].frame[1] = ent.framestate.g[FS_REG].frame[0];
frameduration[r_refdef.currentplayernum] = 0.1;
lerptime[r_refdef.currentplayernum] = realtime;
pv->oldmodel = ent.model;
pv->oldframe = ent.framestate.g[FS_REG].frame[1] = ent.framestate.g[FS_REG].frame[0];
pv->frameduration = 0.1;
pv->lerptime = realtime;
}
ent.framestate.g[FS_REG].lerpfrac = 1-(realtime-lerptime[r_refdef.currentplayernum])/frameduration[r_refdef.currentplayernum];
ent.framestate.g[FS_REG].lerpfrac = 1-(realtime-pv->lerptime)/pv->frameduration;
ent.framestate.g[FS_REG].lerpfrac = bound(0, ent.framestate.g[FS_REG].lerpfrac, 1);
}
@ -4488,9 +4483,9 @@ void CL_LinkViewModel(void)
plnum = -1;
if (cl.spectator)
plnum = Cam_TrackNum(r_refdef.currentplayernum);
plnum = Cam_TrackNum(pv);
if (plnum == -1)
plnum = cl.playernum[r_refdef.currentplayernum];
plnum = r_refdef.playerview->playernum;
plstate = &cl.inframes[parsecountmod].playerstate[plnum];
CLQ1_AddPowerupShell(V_AddEntity(&ent), true, plstate?plstate->effects:0);
@ -4663,14 +4658,13 @@ void CL_SetUpPlayerPrediction(qboolean dopred)
pplayer->active = true;
pplayer->flags = state->flags;
// note that the local player is special, since he moves locally
// we use his last predicted postition
// note that the local players are special, since they move locally
// we use their last predicted postition
for (s = 0; s < cl.splitclients; s++)
{
if (j == cl.playernum[s])
if (j == cl.playerview[s].playernum)
{
VectorCopy(cl.inframes[cls.netchan.outgoing_sequence&UPDATE_MASK].playerstate[cl.playernum[s]].origin,
pplayer->origin);
VectorCopy(cl.inframes[cls.netchan.outgoing_sequence&UPDATE_MASK].playerstate[cl.playerview[s].playernum].origin, pplayer->origin);
break;
}
}

View File

@ -85,7 +85,7 @@ int Player_SlottoId (int slot)
char *Player_MyName (void)
{
return cl.players[cl.playernum[0]].name;
return cl.players[cl.playerview[0].playernum].name;
}
@ -599,8 +599,8 @@ qboolean Ignore_Message(char *s, int flags, int offset)
(int) ignore_opponents.ival == 1 ||
(cls.state >= ca_connected && /*!cl.standby &&*/ !cls.demoplayback && !cl.spectator) // match?
) &&
flags == 1 && !cl.spectator && slot != cl.playernum[0] &&
(!cl.teamplay || strcmp(cl.players[slot].team, cl.players[cl.playernum[0]].team))
flags == 1 && !cl.spectator && slot != cl.playerview[0].playernum &&
(!cl.teamplay || strcmp(cl.players[slot].team, cl.players[cl.playerview[0].playernum].team))
)
{
return true;

View File

@ -228,7 +228,7 @@ void IN_MLookUp (void)
int pnum = CL_TargettedSplit(false);
KeyUp(&in_mlook);
if ( !(in_mlook.state[pnum]&1) && lookspring.ival)
V_StartPitchDrift(pnum);
V_StartPitchDrift(&cl.playerview[pnum]);
}
void IN_UpDown(void) {KeyDown(&in_up);}
void IN_UpUp(void) {KeyUp(&in_up);}
@ -277,10 +277,10 @@ void IN_JumpDown (void)
else
#endif
if (condition && cl.playerview[pnum].stats[STAT_HEALTH] > 0 && !cls.demoplayback && !cl.spectator &&
cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[cl.playernum[pnum]].messagenum == cl.validsequence && cl.waterlevel[pnum] >= 2 && (!cl.teamfortress || !(in_forward.state[pnum] & 1))
cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[cl.playerview[pnum].playernum].messagenum == cl.validsequence && cl.playerview[pnum].waterlevel >= 2 && (!cl.teamfortress || !(in_forward.state[pnum] & 1))
)
KeyDown(&in_up);
else if (condition && cl.spectator && Cam_TrackNum(pnum) == -1)
else if (condition && cl.spectator && Cam_TrackNum(&cl.playerview[pnum]) == -1)
KeyDown(&in_up);
else
KeyDown(&in_jump);
@ -535,7 +535,7 @@ void CL_AdjustAngles (int pnum, double frametime)
}
if (in_klook.state[pnum] & 1)
{
V_StopPitchDrift (pnum);
V_StopPitchDrift (&cl.playerview[pnum]);
quant = cl_pitchspeed.ival;
if (cl.fpd & FPD_LIMIT_PITCH || !ruleset_allow_frj.ival)
quant = bound(-700, quant, 700);
@ -553,7 +553,7 @@ void CL_AdjustAngles (int pnum, double frametime)
cl.playerview[pnum].viewanglechange[PITCH] += speed*cl_pitchspeed.ival * down;
if (up || down)
V_StopPitchDrift (pnum);
V_StopPitchDrift (&cl.playerview[pnum]);
}
/*
@ -1561,11 +1561,11 @@ void CL_SendCmd (double frametime, qboolean mainloop)
// if we are spectator, try autocam
if (cl.spectator)
Cam_Track(plnum, cmd);
Cam_Track(&cl.playerview[plnum], cmd);
CL_FinishMove(cmd, cmd->msec, plnum);
Cam_FinishMove(plnum, cmd);
Cam_FinishMove(&cl.playerview[plnum], cmd);
}
while (clientcmdlist)
@ -1674,8 +1674,8 @@ void CL_SendCmd (double frametime, qboolean mainloop)
// if we are spectator, try autocam
// if (cl.spectator)
Cam_Track(plnum, &independantphysics[plnum]);
Cam_FinishMove(plnum, &independantphysics[plnum]);
Cam_Track(&cl.playerview[plnum], &independantphysics[plnum]);
Cam_FinishMove(&cl.playerview[plnum], &independantphysics[plnum]);
independantphysics[plnum].msec = msecstouse;
}

View File

@ -36,6 +36,8 @@ void Name_Callback(struct cvar_s *var, char *oldvalue);
qboolean noclip_anglehack; // remnant from old quake
void Host_FinishLoading(void);
cvar_t rcon_password = SCVARF("rcon_password", "", CVAR_NOUNSAFEEXPAND);
@ -103,75 +105,75 @@ extern int total_loading_size, current_loading_size, loading_stage;
//
// info mirrors
//
cvar_t password = CVARAF("password", "", "pq_password", CVAR_USERINFO | CVAR_NOUNSAFEEXPAND); //this is parhaps slightly dodgy... added pq_password alias because baker seems to be using this for user accounts.
cvar_t spectator = CVARF("spectator", "", CVAR_USERINFO);
cvar_t name = CVARFC("name", "unnamed", CVAR_ARCHIVE | CVAR_USERINFO, Name_Callback);
cvar_t team = CVARF("team", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t skin = CVARF("skin", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t model = CVARF("model", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t topcolor = CVARF("topcolor", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t bottomcolor = CVARF("bottomcolor", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t rate = CVARFD("rate", "10000"/*"6480"*/, CVAR_ARCHIVE | CVAR_USERINFO, "A rough measure of the bandwidth to try to use while playing. Too high a value may result in 'buffer bloat'.");
cvar_t drate = CVARFD("drate", "100000", CVAR_ARCHIVE | CVAR_USERINFO, "A rough measure of the bandwidth to try to use while downloading."); // :)
cvar_t noaim = CVARF("noaim", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t msg = CVARFD("msg", "1", CVAR_ARCHIVE | CVAR_USERINFO, "Filter console prints/messages. Only functions on QuakeWorld servers. 0=pickup messages. 1=death messages. 2=critical messages. 3=chat.");
cvar_t b_switch = CVARF("b_switch", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t w_switch = CVARF("w_switch", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t cl_nofake = CVARD("cl_nofake", "2", "value 0: permits \\r chars in chat messages\nvalue 1: blocks all \\r chars\nvalue 2: allows \\r chars, but only from teammates");
cvar_t cl_chatsound = CVAR("cl_chatsound","1");
cvar_t cl_enemychatsound = CVAR("cl_enemychatsound", "misc/talk.wav");
cvar_t cl_teamchatsound = CVAR("cl_teamchatsound", "misc/talk.wav");
cvar_t password = CVARAF("password", "", "pq_password", CVAR_USERINFO | CVAR_NOUNSAFEEXPAND); //this is parhaps slightly dodgy... added pq_password alias because baker seems to be using this for user accounts.
cvar_t spectator = CVARF("spectator", "", CVAR_USERINFO);
cvar_t name = CVARFC("name", "unnamed", CVAR_ARCHIVE | CVAR_USERINFO, Name_Callback);
cvar_t team = CVARF("team", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t skin = CVARF("skin", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t model = CVARF("model", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t topcolor = CVARF("topcolor", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t bottomcolor = CVARF("bottomcolor", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t rate = CVARFD("rate", "10000"/*"6480"*/, CVAR_ARCHIVE | CVAR_USERINFO, "A rough measure of the bandwidth to try to use while playing. Too high a value may result in 'buffer bloat'.");
cvar_t drate = CVARFD("drate", "100000", CVAR_ARCHIVE | CVAR_USERINFO, "A rough measure of the bandwidth to try to use while downloading."); // :)
cvar_t noaim = CVARF("noaim", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t msg = CVARFD("msg", "1", CVAR_ARCHIVE | CVAR_USERINFO, "Filter console prints/messages. Only functions on QuakeWorld servers. 0=pickup messages. 1=death messages. 2=critical messages. 3=chat.");
cvar_t b_switch = CVARF("b_switch", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t w_switch = CVARF("w_switch", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t cl_nofake = CVARD("cl_nofake", "2", "value 0: permits \\r chars in chat messages\nvalue 1: blocks all \\r chars\nvalue 2: allows \\r chars, but only from teammates");
cvar_t cl_chatsound = CVAR("cl_chatsound","1");
cvar_t cl_enemychatsound = CVAR("cl_enemychatsound", "misc/talk.wav");
cvar_t cl_teamchatsound = CVAR("cl_teamchatsound", "misc/talk.wav");
cvar_t r_torch = CVARF("r_torch", "0", CVAR_CHEAT);
cvar_t r_rocketlight = CVARFC("r_rocketlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback);
cvar_t r_lightflicker = CVAR("r_lightflicker", "1");
cvar_t cl_r2g = CVARF("cl_r2g", "0", CVAR_ARCHIVE);
cvar_t r_powerupglow = CVAR("r_powerupglow", "1");
cvar_t v_powerupshell = CVARF("v_powerupshell", "0", CVAR_ARCHIVE);
cvar_t cl_gibfilter = CVARF("cl_gibfilter", "0", CVAR_ARCHIVE);
cvar_t cl_deadbodyfilter = CVAR("cl_deadbodyfilter", "0");
cvar_t r_torch = CVARF("r_torch", "0", CVAR_CHEAT);
cvar_t r_rocketlight = CVARFC("r_rocketlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback);
cvar_t r_lightflicker = CVAR("r_lightflicker", "1");
cvar_t cl_r2g = CVARF("cl_r2g", "0", CVAR_ARCHIVE);
cvar_t r_powerupglow = CVAR("r_powerupglow", "1");
cvar_t v_powerupshell = CVARF("v_powerupshell", "0", CVAR_ARCHIVE);
cvar_t cl_gibfilter = CVARF("cl_gibfilter", "0", CVAR_ARCHIVE);
cvar_t cl_deadbodyfilter = CVAR("cl_deadbodyfilter", "0");
cvar_t cl_gunx = SCVAR("cl_gunx", "0");
cvar_t cl_guny = SCVAR("cl_guny", "0");
cvar_t cl_gunz = SCVAR("cl_gunz", "0");
cvar_t cl_gunx = CVAR("cl_gunx", "0");
cvar_t cl_guny = CVAR("cl_guny", "0");
cvar_t cl_gunz = CVAR("cl_gunz", "0");
cvar_t cl_gunanglex = SCVAR("cl_gunanglex", "0");
cvar_t cl_gunangley = SCVAR("cl_gunangley", "0");
cvar_t cl_gunanglez = SCVAR("cl_gunanglez", "0");
cvar_t cl_gunanglex = CVAR("cl_gunanglex", "0");
cvar_t cl_gunangley = CVAR("cl_gunangley", "0");
cvar_t cl_gunanglez = CVAR("cl_gunanglez", "0");
cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available.");
cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. 2 allows redirection only to named packages files. Also allows the server to send nearly arbitary download commands.");
cvar_t cl_download_mapsrc = CVARD("cl_download_mapsrc", "", "Specifies an http location prefix for map downloads. EG: \"http://bigfoot.morphos-team.net/misc/quakemaps/\"");
cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)");
cvar_t requiredownloads = CVARFD("requiredownloads","1", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining.");
cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages.");
cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. 2 allows redirection only to named packages files. Also allows the server to send nearly arbitary download commands.");
cvar_t cl_download_mapsrc = CVARD("cl_download_mapsrc", "", "Specifies an http location prefix for map downloads. EG: \"http://bigfoot.morphos-team.net/misc/quakemaps/\"");
cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)");
cvar_t requiredownloads = CVARFD("requiredownloads","1", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining.");
cvar_t cl_muzzleflash = SCVAR("cl_muzzleflash", "1");
cvar_t cl_muzzleflash = CVAR("cl_muzzleflash", "1");
cvar_t cl_item_bobbing = CVARF("cl_model_bobbing", "0", CVAR_ARCHIVE);
cvar_t cl_countpendingpl = SCVAR("cl_countpendingpl", "0");
cvar_t cl_item_bobbing = CVARF("cl_model_bobbing", "0", CVAR_ARCHIVE);
cvar_t cl_countpendingpl = CVARD("cl_countpendingpl", "0", "If set to 1, packet loss percentages will show packets still in transit as lost, even if they might still be received.");
cvar_t cl_standardchat = CVARFD("cl_standardchat", "0", CVAR_ARCHIVE, "Disables auto colour coding in chat messages.");
cvar_t msg_filter = CVARD("msg_filter", "0", "Filter out chat messages: 0=neither. 1=broadcast chat. 2=team chat. 3=all chat.");
cvar_t cl_standardmsg = CVARFD("cl_standardmsg", "0", CVAR_ARCHIVE, "Disables auto colour coding in console prints.");
cvar_t cl_parsewhitetext = CVARD("cl_parsewhitetext", "1", "When parsing chat messages, enable support for messages like: red{white}red");
cvar_t cl_standardchat = CVARFD("cl_standardchat", "0", CVAR_ARCHIVE, "Disables auto colour coding in chat messages.");
cvar_t msg_filter = CVARD("msg_filter", "0", "Filter out chat messages: 0=neither. 1=broadcast chat. 2=team chat. 3=all chat.");
cvar_t cl_standardmsg = CVARFD("cl_standardmsg", "0", CVAR_ARCHIVE, "Disables auto colour coding in console prints.");
cvar_t cl_parsewhitetext = CVARD("cl_parsewhitetext", "1", "When parsing chat messages, enable support for messages like: red{white}red");
cvar_t cl_dlemptyterminate = CVAR("cl_dlemptyterminate", "1");
cvar_t cl_dlemptyterminate = CVAR("cl_dlemptyterminate", "1");
cvar_t host_mapname = CVARAF("mapname", "",
"host_mapname", 0);
cvar_t host_mapname = CVARAF("mapname", "",
"host_mapname", 0);
cvar_t ruleset_allow_playercount = SCVAR("ruleset_allow_playercount", "1");
cvar_t ruleset_allow_frj = SCVAR("ruleset_allow_frj", "1");
cvar_t ruleset_allow_semicheats = SCVAR("ruleset_allow_semicheats", "1");
cvar_t ruleset_allow_packet = SCVAR("ruleset_allow_packet", "1");
cvar_t ruleset_allow_particle_lightning = SCVAR("ruleset_allow_particle_lightning", "1");
cvar_t ruleset_allow_overlongsounds = SCVAR("ruleset_allow_overlong_sounds", "1");
cvar_t ruleset_allow_larger_models = SCVAR("ruleset_allow_larger_models", "1");
cvar_t ruleset_allow_modified_eyes = SCVAR("ruleset_allow_modified_eyes", "0");
cvar_t ruleset_allow_sensative_texture_replacements = SCVAR("ruleset_allow_sensative_texture_replacements", "1");
cvar_t ruleset_allow_localvolume = SCVAR("ruleset_allow_localvolume", "1");
cvar_t ruleset_allow_shaders = SCVARF("ruleset_allow_shaders", "1", CVAR_SHADERSYSTEM);
cvar_t ruleset_allow_fbmodels = SCVARF("ruleset_allow_fbmodels", "1", CVAR_SHADERSYSTEM);
cvar_t ruleset_allow_playercount = CVAR("ruleset_allow_playercount", "1");
cvar_t ruleset_allow_frj = CVAR("ruleset_allow_frj", "1");
cvar_t ruleset_allow_semicheats = CVAR("ruleset_allow_semicheats", "1");
cvar_t ruleset_allow_packet = CVAR("ruleset_allow_packet", "1");
cvar_t ruleset_allow_particle_lightning = CVAR("ruleset_allow_particle_lightning", "1");
cvar_t ruleset_allow_overlongsounds = CVAR("ruleset_allow_overlong_sounds", "1");
cvar_t ruleset_allow_larger_models = CVAR("ruleset_allow_larger_models", "1");
cvar_t ruleset_allow_modified_eyes = CVAR("ruleset_allow_modified_eyes", "0");
cvar_t ruleset_allow_sensative_texture_replacements = CVAR("ruleset_allow_sensative_texture_replacements", "1");
cvar_t ruleset_allow_localvolume = CVAR("ruleset_allow_localvolume", "1");
cvar_t ruleset_allow_shaders = CVARF("ruleset_allow_shaders", "1", CVAR_SHADERSYSTEM);
cvar_t ruleset_allow_fbmodels = CVARF("ruleset_allow_fbmodels", "1", CVAR_SHADERSYSTEM);
extern cvar_t cl_hightrack;
extern cvar_t vid_renderer;
@ -274,13 +276,13 @@ void CL_UpdateWindowTitle(void)
default:
#ifndef CLIENTONLY
if (sv.state)
VID_SetWindowCaption(va("%s %s: %s", DISTRIBUTION, fs_gamename.string, sv.name));
VID_SetWindowCaption(va("%s", fs_gamename.string, sv.name));
else
#endif
VID_SetWindowCaption(va("%s %s: %s", DISTRIBUTION, fs_gamename.string, cls.servername));
VID_SetWindowCaption(va("%s: %s", fs_gamename.string, cls.servername));
break;
case ca_disconnected:
VID_SetWindowCaption(va("%s %s: disconnected", DISTRIBUTION, fs_gamename.string));
VID_SetWindowCaption(va("%s: disconnected", fs_gamename.string));
break;
}
}
@ -775,6 +777,8 @@ void CL_CheckForResend (void)
return;
}
CL_FlushClientCommands();
t2 = Sys_DoubleTime ();
connect_time = realtime+t2-t1; // for retransmit requests
@ -1109,7 +1113,7 @@ void CL_ClearState (void)
T_FreeInfoStrings();
SCR_ShowPic_Clear();
if (cl.playernum[0] == -1)
if (cl.playerview[0].playernum == -1)
{ //left over from q2 connect.
Media_StopFilm(true);
}
@ -1172,7 +1176,7 @@ void CL_ClearState (void)
for (i = 0; i < MAX_SPLITS; i++)
{
VectorSet(cl.playerview[i].gravitydir, 0, 0, -1);
cl.viewheight[i] = DEFAULT_VIEWHEIGHT;
cl.playerview[i].viewheight = DEFAULT_VIEWHEIGHT;
}
cl.minpitch = -70;
cl.maxpitch = 80;
@ -1313,6 +1317,8 @@ void CL_Disconnect (void)
CL_ClearState();
FS_PureMode(0, NULL, NULL, 0);
//now start up the csqc/menu module again.
CSQC_UnconnectedInit();
}
@ -1373,7 +1379,7 @@ void CL_User_f (void)
if (cls.protocol == CP_NETQUAKE)
Con_Printf("name: %s\ncolour %i %i\nping: %i\n", cl.players[i].name, cl.players[i].rbottomcolor, cl.players[i].rtopcolor, cl.players[i].ping);
else
Info_Print (cl.players[i].userinfo);
Info_Print (cl.players[i].userinfo, "");
found = true;
}
}
@ -1455,7 +1461,7 @@ void CL_Color_f (void)
bottom = CL_ParseColour(Cmd_Argv(2));
}
Q_snprintfz (num, sizeof(num), (top&0xff000000)?"%#08x":"%i", top & 0xffffff);
Q_snprintfz (num, sizeof(num), (top&0xff000000)?"0x%06x":"%i", top & 0xffffff);
if (top == 0)
*num = '\0';
if (Cmd_ExecLevel>RESTRICT_SERVER) //colour command came from server for a split client
@ -1464,7 +1470,7 @@ void CL_Color_f (void)
// Cvar_LockFromServer(&topcolor, num);
else
Cvar_Set (&topcolor, num);
Q_snprintfz (num, sizeof(num), (bottom&0xff000000)?"%#08x":"%i", bottom & 0xffffff);
Q_snprintfz (num, sizeof(num), (bottom&0xff000000)?"0x%06x":"%i", bottom & 0xffffff);
if (bottom == 0)
*num = '\0';
if (Cmd_ExecLevel>RESTRICT_SERVER) //colour command came from server for a split client
@ -1479,7 +1485,6 @@ void CL_Color_f (void)
#endif
}
void FS_GenCachedPakName(char *pname, char *crc, char *local, int llen);
qboolean CL_CheckDLFile(char *filename);
void CL_PakDownloads(int mode)
{
@ -1513,7 +1518,8 @@ void CL_PakDownloads(int mode)
/*if we already have such a file, this is a no-op*/
if (CL_CheckDLFile(va("package/%s", pname)))
continue;
FS_GenCachedPakName(pname, com_token, local, sizeof(local));
if (!FS_GenCachedPakName(pname, com_token, local, sizeof(local)))
continue;
}
else
Q_strncpyz(local, pname, sizeof(local));
@ -1523,26 +1529,27 @@ void CL_PakDownloads(int mode)
void CL_CheckServerPacks(void)
{
static qboolean oldpure;
qboolean pure = cl_pure.ival || atoi(Info_ValueForKey(cl.serverinfo, "sv_pure"));
static int oldpure;
int pure = atof(Info_ValueForKey(cl.serverinfo, "sv_pure"))*2;
if (pure < cl_pure.ival)
pure = cl_pure.ival;
pure = bound(0, pure, 2);
if (!*cl.serverpakcrcs || cls.demoplayback)
pure = 0;
if (pure != oldpure || cl.serverpakschanged)
{
CL_PakDownloads((pure && !cl_download_packages.ival)?1:cl_download_packages.ival);
FS_PureMode(pure, cl.serverpaknames, cl.serverpakcrcs, cls.challenge);
if (pure)
{
CL_PakDownloads((!cl_download_packages.ival)?1:cl_download_packages.ival);
FS_ForceToPure(cl.serverpaknames, cl.serverpakcrcs, cls.challenge);
/*when enabling pure, kill cached models/sounds/etc*/
Cache_Flush();
/*make sure cheating lamas can't use old shaders from a different srver*/
Shader_NeedReload(true);
}
else
{
CL_PakDownloads(cl_download_packages.ival);
FS_ImpurePacks(cl.serverpaknames, cl.serverpakcrcs);
}
}
oldpure = pure;
cl.serverpakschanged = false;
@ -1836,7 +1843,7 @@ void CL_SetInfo_f (void)
int pnum = CL_TargettedSplit(true);
if (Cmd_Argc() == 1)
{
Info_Print (cls.userinfo[pnum]);
Info_Print (cls.userinfo[pnum], "");
return;
}
if (Cmd_Argc() != 3)
@ -2347,12 +2354,14 @@ void CL_ConnectionlessPacket (void)
#ifdef Q3CLIENT
else if (!strcmp(com_token, "onnectResponse"))
{
cls.protocol = CP_QUAKE3;
goto client_connect;
}
#endif
#ifdef Q2CLIENT
else if (!strcmp(com_token, "lient_connect"))
{
cls.protocol = CP_QUAKE2;
goto client_connect;
}
#endif
@ -2429,6 +2438,7 @@ void CL_ConnectionlessPacket (void)
}
else if (!strcmp(s, "client_connect"))
{
cls.protocol = CP_QUAKE2;
goto client_connect;
}
else if (!strcmp(s, "disconnect"))
@ -2497,6 +2507,7 @@ void CL_ConnectionlessPacket (void)
{
int compress;
int mtu;
cls.protocol = CP_QUAKEWORLD;
#ifdef Q2CLIENT
client_connect: //fixme: make function
#endif
@ -2684,7 +2695,7 @@ void CLNQ_ConnectionlessPacket(void)
#endif
void CL_MVDUpdateSpectator (void);
void CL_WriteDemoMessage (sizebuf_t *msg);
/*
=================
CL_ReadPackets
@ -2741,6 +2752,8 @@ void CL_ReadPackets (void)
if (cls.state == ca_disconnected)
{ //connect to nq servers, but don't get confused with sequenced packets.
if (NET_WasSpecialPacket(NS_CLIENT))
continue;
#ifdef NQPROT
CLNQ_ConnectionlessPacket ();
#endif
@ -2799,6 +2812,8 @@ void CL_ReadPackets (void)
else if (!Netchan_Process(&cls.netchan))
continue; // wasn't accepted for some reason
CL_WriteDemoMessage (&net_message);
if (cls.netchan.incoming_sequence > cls.netchan.outgoing_sequence)
{ //server should not be responding to packets we have not sent yet
Con_DPrintf("Server is from the future! (%i packets)\n", cls.netchan.incoming_sequence - cls.netchan.outgoing_sequence);
@ -3061,7 +3076,7 @@ void CL_ServerInfo_f(void)
{
if (cls.demoplayback || cls.protocol != CP_QUAKEWORLD)
{
Info_Print (cl.serverinfo);
Info_Print (cl.serverinfo, "");
}
else
Cmd_ForwardToServer ();
@ -3164,7 +3179,6 @@ void CL_Init (void)
Cvar_Register (&cl_servername, cl_controlgroup);
Cvar_Register (&cl_serveraddress, cl_controlgroup);
Cvar_Register (&cl_demospeed, "Demo playback");
Cvar_Register (&cl_warncmd, "Warnings");
Cvar_Register (&cl_upspeed, cl_inputgroup);
Cvar_Register (&cl_forwardspeed, cl_inputgroup);
Cvar_Register (&cl_backspeed, cl_inputgroup);
@ -3526,6 +3540,395 @@ qboolean Host_SimulationTime(float time)
}
#endif
void Host_RunFileNotify(struct dl_download *dl)
{
if (dl->file)
{
Host_RunFile(dl->url, strlen(dl->url), dl->file);
dl->file = NULL;
}
}
#include "fs.h"
#define HRF_OVERWRITE 1
#define HRF_NOOVERWRITE 2
#define HRF_ABORT 4
#define HRF_OPENED 8
#define HRF_ACTION (HRF_OVERWRITE|HRF_NOOVERWRITE|HRF_ABORT)
typedef struct {
char ext[4]; //FIXME: override by mime types
unsigned int flags;
vfsfile_t *srcfile;
vfsfile_t *dstfile;
char fname[1]; //system path or url.
} hrf_t;
void Host_DoRunFile(hrf_t *f);
void Host_RunFileDownloaded(struct dl_download *dl)
{
hrf_t *f = dl->user_ctx;
f->srcfile = dl->file;
dl->file = NULL;
Host_DoRunFile(f);
}
void Host_RunFilePrompted(void *ctx, int button)
{
hrf_t *f = ctx;
switch(button)
{
case 0:
f->flags |= HRF_OVERWRITE;
break;
case 1:
f->flags |= HRF_NOOVERWRITE;
break;
default:
f->flags |= HRF_ABORT;
break;
}
Host_DoRunFile(f);
}
qboolean waitingformanifest;
void Host_DoRunFile(hrf_t *f)
{
char qname[MAX_QPATH];
char displayname[MAX_QPATH];
char loadcommand[MAX_OSPATH];
qboolean isnew = false;
qboolean haschanged = false;
if (f->flags & HRF_ABORT)
{
if (f->srcfile)
VFS_CLOSE(f->srcfile);
if (f->dstfile)
VFS_CLOSE(f->dstfile);
Z_Free(f);
return;
}
if (!strcmp(f->ext, "qwd") || !strcmp(f->ext, "dem") || !strcmp(f->ext, "mvd"))
{
//play directly via system path, no prompts needed
Cbuf_AddText(va("playdemo \"#%s\"\n", f->fname), RESTRICT_LOCAL);
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
else if (!strcmp(f->ext, "qtv"))
{
//play directly via url/system path, no prompts needed
Cbuf_AddText(va("qtvplay \"#%s\"\n", f->fname), RESTRICT_LOCAL);
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
else if (!strcmp(f->ext, "bsp"))
{
char shortname[MAX_QPATH];
COM_StripExtension(COM_SkipPath(f->fname), shortname, sizeof(shortname));
snprintf(qname, sizeof(qname), "maps/%s.bsp", shortname);
snprintf(loadcommand, sizeof(loadcommand), "map \"%s\"\n", shortname);
snprintf(displayname, sizeof(displayname), "map: %s", shortname);
}
else if (!strcmp(f->ext, "pak") || !strcmp(f->ext, "pk3"))
{
char *shortname;
shortname = COM_SkipPath(f->fname);
snprintf(qname, sizeof(qname), "%s", shortname);
snprintf(loadcommand, sizeof(loadcommand), "fs_restart\n");
snprintf(displayname, sizeof(displayname), "package: %s", shortname);
}
else if (!strcmp(f->ext, "fmf"))
{
if (f->flags & HRF_OPENED)
{
waitingformanifest--;
if (f->srcfile)
{
ftemanifest_t *man;
int len = VFS_GETLEN(f->srcfile);
char *fdata = BZ_Malloc(len+1);
VFS_READ(f->srcfile, fdata, len);
VFS_CLOSE(f->srcfile);
fdata[len] = 0;
man = FS_Manifest_Parse(fdata);
if (!man->updateurl)
man->updateurl = Z_StrDup(f->fname);
BZ_Free(fdata);
FS_ChangeGame(man, true);
return;
}
}
}
else
{
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
if (!(f->flags & HRF_OPENED))
{
f->flags |= HRF_OPENED;
if (!f->srcfile)
{
#ifdef WEBCLIENT
if (!strncmp(f->fname, "http://", 7))
{
struct dl_download *dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded);
dl->user_ctx = f;
return;
}
#endif
f->srcfile = VFSOS_Open(f->fname, "rb"); //input file is a system path, or something.
}
}
if (!f->srcfile)
{
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
VFS_SEEK(f->srcfile, 0);
COM_StripExtension(COM_SkipPath(f->fname), qname, sizeof(qname));
f->dstfile = FS_OpenVFS(qname, "rb", FS_GAME);
if (f->dstfile)
{
//do a real diff.
if (VFS_GETLEN(f->srcfile) != VFS_GETLEN(f->dstfile))
haschanged = true;
else
{
int len = VFS_GETLEN(f->srcfile);
char sbuf[8192], dbuf[8192];
if (len > sizeof(sbuf))
len = sizeof(sbuf);
VFS_READ(f->srcfile, sbuf, len);
VFS_READ(f->dstfile, dbuf, len);
haschanged = memcmp(sbuf, dbuf, len);
}
VFS_SEEK(f->srcfile, 0);
VFS_CLOSE(f->dstfile);
f->dstfile = NULL;
}
else
isnew = true;
if (haschanged)
{
if (!(f->flags & HRF_ACTION))
{
M_Menu_Prompt(Host_RunFilePrompted, f, "File already exists.", "What would you like to do?", displayname, "Overwrite", "Run old", "Cancel");
return;
}
}
else if (isnew)
{
if (!(f->flags & HRF_ACTION))
{
M_Menu_Prompt(Host_RunFilePrompted, f, "File appears new.", "Would you like to install", displayname, "Install!", "", "Cancel");
return;
}
}
if (f->flags & HRF_OVERWRITE)
{
char buffer[8192];
int len;
f->dstfile = FS_OpenVFS(qname, "wb", FS_GAMEONLY);
if (f->dstfile)
{
while(1)
{
len = VFS_READ(f->srcfile, buffer, sizeof(buffer));
if (len <= 0)
break;
VFS_WRITE(f->dstfile, buffer, len);
}
VFS_CLOSE(f->dstfile);
f->dstfile = NULL;
}
}
Cbuf_AddText(loadcommand, RESTRICT_LOCAL);
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
//only valid once the host has been initialised, as it needs a working filesystem.
//if file is specified, takes full ownership of said file, including destruction.
qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
{
char *ext = COM_FileExtension(fname);
hrf_t *f = Z_Malloc(sizeof(*f) + nlen);
memcpy(f->fname, fname, nlen);
f->fname[nlen] = 0;
Q_strncpyz(f->ext, ext, sizeof(f->ext));
Host_DoRunFile(f);
return true;
#if 0
char buffer[MAX_OSPATH];
char *ext;
if (nlen >= MAX_OSPATH)
{
if (file)
VFS_CLOSE(file);
Con_Printf("Filename too long.\n");
return true;
}
memcpy(buffer, fname, nlen);
buffer[nlen] = 0;
fname = buffer;
ext = COM_FileExtension(fname);
if (!strncmp(fname, "qw:", 3))
{
fname += 3;
if (!strncmp(fname, "//", 2))
fname += 2;
ext = strchr(fname, '/'); //this also protects us against irc urls, etc. unsure if that's important right now.
if (ext)
*ext = 0;
Con_Printf("QW stream: \"%s\"\n", fname);
Cbuf_AddText(va("connect \"%s\"\n", fname), RESTRICT_LOCAL);
}
else if (!strcmp(ext, "qwd") || !strcmp(ext, "dem") || !strcmp(ext, "mvd"))
Cbuf_AddText(va("playdemo \"#%s\"\n", fname), RESTRICT_LOCAL);
else if (!strcmp(ext, "bsp") || !strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4") || !strcmp(ext, "fmf"))
{
extern qboolean waitingformanifest;
//these must all have a valid source file. just recurse if its not set.
if (!file)
{
if (!strncmp(fname, "http://", 7))
{
if (HTTP_CL_Get(fname, NULL, Host_RunFileNotify))
{
if (!strcmp(ext, "fmf"))
waitingformanifest = true;
return true;
}
return false;
}
if (!strncmp(fname, "file://", 7))
fname += 7;
file = VFSOS_Open(fname, "rb"); //input file is a system path, or something.
if (file)
{
Host_RunFile(fname, strlen(fname), file);
return true;
}
return false;
}
if (!strcmp(ext, "fmf"))
{
CL_Manifest_Parse(file, fname);
waitingformanifest = false;
}
else if (!strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4"))
{
//open the archive, look for a *readme.txt
//look for a -game inside that.
//if found, install the pak there.
//if a +map is found, load that map after install.
Con_Printf("Unable to install paks/pk3s at this time\n");
}
else if (!strcmp(ext, "bsp"))
{
char qname[MAX_QPATH];
vfsfile_t *qf;
qboolean overwrite = false;
COM_StripExtension(COM_SkipPath(fname), qname, sizeof(qname));
qf = FS_OpenVFS(va("maps/%s.bsp", qname), "rb", FS_GAME);
if (qf)
{
if (VFS_GETLEN(file) != VFS_GETLEN(qf))
overwrite = true;
VFS_SEEK(file, 0);
VFS_CLOSE(qf);
}
#ifdef _WIN32
if (overwrite)
{
switch(MessageBox(mainwindow, va("Overwrite existing map: %s?", qname), "Install And Play", MB_YESNOCANCEL))
{
case IDYES:
//overwrite it and load it up
overwrite = true;
break;
case IDNO:
//load up the old version
overwrite = false;
break;
default:
case IDCANCEL:
//quit or something
return false;
}
}
else if (!qf)
{
switch(MessageBox(mainwindow, va("Install new map: %s?", qname), "Install And Play", MB_OKCANCEL))
{
case IDOK:
//overwrite it and load it up
overwrite = true;
break;
default:
case IDCANCEL:
//quit or something
return false;
}
}
if (overwrite)
{
char buffer[8192];
int len;
qf = FS_OpenVFS(va("maps/%s.bsp", qname), "wb", FS_GAMEONLY);
if (qf)
{
while(1)
{
len = VFS_READ(file, buffer, sizeof(buffer));
if (len <= 0)
break;
VFS_WRITE(qf, buffer, len);
}
VFS_CLOSE(qf);
}
}
Cbuf_AddText(va("map \"%s\"\n", qname), RESTRICT_LOCAL);
#endif
}
}
else
Cbuf_AddText(va("qtvplay \"#%s\"\n", fname), RESTRICT_LOCAL);
if (file)
VFS_CLOSE(file);
return true;
#endif
}
/*
==================
Host_Frame
@ -3550,6 +3953,7 @@ double Host_Frame (double time)
float maxfps;
qboolean maxfpsignoreserver;
qboolean idle;
extern qboolean r_blockvidrestart;
RSpeedLocals();
@ -3575,6 +3979,15 @@ double Host_Frame (double time)
HTTP_CL_Think();
#endif
if (r_blockvidrestart)
{
extern qboolean waitingformanifest;
if (waitingformanifest)
return 0.1;
Host_FinishLoading();
return 0;
}
#ifdef PLUGINS
Plug_Tick();
#endif
@ -3706,6 +4119,10 @@ double Host_Frame (double time)
{
IN_Move(NULL, 0);
CL_CheckForResend ();
#ifdef VOICECHAT
S_Voip_Transmit(0, NULL);
#endif
}
else
{
@ -3855,7 +4272,7 @@ void CL_StartCinematicOrMenu(void)
UI_Start();
#endif
Con_TPrintf (TLC_QUAKEWORLD_INITED, fs_gamename.string);
Con_TPrintf (TLC_QUAKEWORLD_INITED, *fs_gamename.string?fs_gamename.string:"Nothing");
//there might be some console command or somesuch waiting for the renderer to begin (demos or map command or whatever all need model support).
realtime+=1;
@ -3905,13 +4322,48 @@ void CL_StartCinematicOrMenu(void)
}
}
//note that this does NOT include commandline.
void CL_ExecInitialConfigs(void)
void CL_ArgumentOverrides(void)
{
int qrc, hrc, def, i;
int i;
if (COM_CheckParm ("-window") || COM_CheckParm ("-startwindowed"))
Cvar_Set(Cvar_FindVar("vid_fullscreen"), "0");
if (COM_CheckParm ("-fullscreen"))
Cvar_Set(Cvar_FindVar("vid_fullscreen"), "1");
if ((i = COM_CheckParm ("-width"))) //width on it's own also sets height
{
Cvar_Set(Cvar_FindVar("vid_width"), com_argv[i+1]);
Cvar_SetValue(Cvar_FindVar("vid_height"), (atoi(com_argv[i+1])/4)*3);
}
if ((i = COM_CheckParm ("-height")))
Cvar_Set(Cvar_FindVar("vid_height"), com_argv[i+1]);
if ((i = COM_CheckParm ("-conwidth"))) //width on it's own also sets height
{
Cvar_Set(Cvar_FindVar("vid_conwidth"), com_argv[i+1]);
Cvar_SetValue(Cvar_FindVar("vid_conheight"), (atoi(com_argv[i+1])/4)*3);
}
if ((i = COM_CheckParm ("-conheight")))
Cvar_Set(Cvar_FindVar("vid_conheight"), com_argv[i+1]);
if ((i = COM_CheckParm ("-bpp")))
Cvar_Set(Cvar_FindVar("vid_bpp"), com_argv[i+1]);
if (COM_CheckParm ("-current"))
Cvar_Set(Cvar_FindVar("vid_desktopsettings"), "1");
}
//note that this does NOT include commandline.
void CL_ExecInitialConfigs(char *resetcommand)
{
int qrc, hrc, def;
Cbuf_AddText ("cl_warncmd 0\n", RESTRICT_LOCAL);
Cmd_ExecuteString("unbindall", RESTRICT_LOCAL);
Cmd_ExecuteString("cvarreset *", RESTRICT_LOCAL);
Cmd_ExecuteString(resetcommand, RESTRICT_LOCAL);
//who should we imitate?
qrc = COM_FDepthFile("quake.rc", true); //q1
hrc = COM_FDepthFile("hexen.rc", true); //h2
@ -3945,39 +4397,44 @@ void CL_ExecInitialConfigs(void)
//assuming they didn't use any waits in their config (fools)
//the configs should be fully loaded.
//so convert the backwards compable commandline parameters in cvar sets.
if (COM_CheckParm ("-window") || COM_CheckParm ("-startwindowed"))
Cvar_Set(Cvar_FindVar("vid_fullscreen"), "0");
if (COM_CheckParm ("-fullscreen"))
Cvar_Set(Cvar_FindVar("vid_fullscreen"), "1");
if ((i = COM_CheckParm ("-width"))) //width on it's own also sets height
{
Cvar_Set(Cvar_FindVar("vid_width"), com_argv[i+1]);
Cvar_SetValue(Cvar_FindVar("vid_height"), (atoi(com_argv[i+1])/4)*3);
}
if ((i = COM_CheckParm ("-height")))
Cvar_Set(Cvar_FindVar("vid_height"), com_argv[i+1]);
if ((i = COM_CheckParm ("-conwidth"))) //width on it's own also sets height
{
Cvar_Set(Cvar_FindVar("vid_conwidth"), com_argv[i+1]);
Cvar_SetValue(Cvar_FindVar("vid_conheight"), (atoi(com_argv[i+1])/4)*3);
}
if ((i = COM_CheckParm ("-conheight")))
Cvar_Set(Cvar_FindVar("vid_conheight"), com_argv[i+1]);
if ((i = COM_CheckParm ("-bpp")))
Cvar_Set(Cvar_FindVar("vid_bpp"), com_argv[i+1]);
if (COM_CheckParm ("-current"))
Cvar_Set(Cvar_FindVar("vid_desktopsettings"), "1");
// Cbuf_Execute (); //if the server initialisation causes a problem, give it a place to abort to
CL_ArgumentOverrides();
}
void Host_FinishLoading(void)
{
//the filesystem has retrieved its manifest, but might still be waiting for paks to finish downloading.
//make sure the filesystem has some default if no manifest was loaded.
FS_ChangeGame(NULL, true);
Con_History_Load();
Cmd_StuffCmds();
Cbuf_Execute ();
CL_ArgumentOverrides();
Con_TPrintf (TL_NL);
Con_Printf ("%s", version_string());
Con_TPrintf (TL_NL);
Con_DPrintf("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."
"\n"
"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. "
"\n"
"See the GNU General Public License for more details.\n");
Renderer_Start();
CL_StartCinematicOrMenu();
}
/*
====================
@ -3986,7 +4443,8 @@ Host_Init
*/
void Host_Init (quakeparms_t *parms)
{
qboolean downloading = false;
int man;
com_parseutf8.ival = 1; //enable utf8 parsing even before cvars are registered.
COM_InitArgv (parms->argc, parms->argv);
@ -4014,6 +4472,7 @@ void Host_Init (quakeparms_t *parms)
Cbuf_Init ();
Cmd_Init ();
V_Init ();
NET_Init ();
COM_Init ();
#ifdef Q2BSPS
CM_Init();
@ -4023,7 +4482,6 @@ void Host_Init (quakeparms_t *parms)
#endif
Host_FixupModelNames();
NET_Init ();
NET_InitClient ();
Netchan_Init ();
Renderer_Init();
@ -4077,42 +4535,11 @@ void Host_Init (quakeparms_t *parms)
Sys_SendKeyEvents();
//the engine is fully running, except the file system may be nulled out waiting for a manifest to download.
//the engine is technically initialised at this point, except for the renderer. now we exec configs and bring up the renderer
//anything that needs models cannot be run yet, but it should be safe to allow console commands etc.
//if we get a map command, we'll just stick it on the end of the console command buffer.
Con_History_Load();
CL_ExecInitialConfigs();
if (CL_CheckBootDownloads())
{
Cmd_StuffCmds();
Cbuf_Execute ();
}
else
downloading = true;
Con_TPrintf (TL_NL);
Con_Printf ("%s", version_string());
Con_TPrintf (TL_NL);
Con_DPrintf("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."
"\n"
"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. "
"\n"
"See the GNU General Public License for more details.\n");
Renderer_Start();
if (!downloading)
CL_StartCinematicOrMenu();
man = COM_CheckParm("-manifest");
if (man && man < com_argc-1 && com_argv[man+1])
Host_RunFile(com_argv[man+1], strlen(com_argv[man+1]), NULL);
}
/*
@ -4159,6 +4586,10 @@ void Host_Shutdown(void)
NET_Shutdown ();
#endif
#ifdef Q3CLIENT
VMQ3_FlushStringHandles();
#endif
Cvar_Shutdown();
Validation_FlushFileList();

View File

@ -603,17 +603,7 @@ void CL_DownloadFinished(void)
Con_Printf("Couldn't rename %s to %s\n", nativetmp, nativefinal);
}
}
else if (strncmp(tempname,"skins/",6))
{
if (!FS_Rename(tempname, filename, FS_GAME))
{
char nativetmp[MAX_OSPATH], nativefinal[MAX_OSPATH];;
FS_NativePath(tempname, FS_GAME, nativetmp, sizeof(nativetmp));
FS_NativePath(filename, FS_GAME, nativefinal, sizeof(nativefinal));
Con_Printf("Couldn't rename %s to %s\n", nativetmp, nativefinal);
}
}
else
else if (!strncmp(tempname,"skins/",6))
{
if (!FS_Rename(tempname+6, filename+6, FS_SKINS))
{
@ -623,6 +613,16 @@ void CL_DownloadFinished(void)
Con_Printf("Couldn't rename %s to %s\n", nativetmp, nativefinal);
}
}
else
{
if (!FS_Rename(tempname, filename, FS_GAME))
{
char nativetmp[MAX_OSPATH], nativefinal[MAX_OSPATH];;
FS_NativePath(tempname, FS_GAME, nativetmp, sizeof(nativetmp));
FS_NativePath(filename, FS_GAME, nativefinal, sizeof(nativefinal));
Con_Printf("Couldn't rename %s to %s\n", nativetmp, nativefinal);
}
}
}
}
@ -734,10 +734,11 @@ qboolean CL_CheckOrEnqueDownloadFile (char *filename, char *localname, unsigned
if (flags & DLLF_NONGAME)
{
/*pak/pk3 downloads have an explicit leading package/ as an internal/network marker*/
filename = va("package/%s", filename);
if (!strchr(filename, ':'))
filename = va("package/%s", filename);
localname = va("package/%s", localname);
}
/*files with a leading * should not be downloaded (inline models, sexed sounds, etc)*/
/*files with a leading * should not be downloaded (inline models, sexed sounds, etc). also block anyone trying to explicitly download a package/ because our code (wrongly) uses that name internally*/
else if (*filename == '*' || !strncmp(filename, "package/", 8))
return true;
@ -1101,7 +1102,7 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
endstage();
}
if (cl.playernum[0] == -1)
if (cl.playerview[0].playernum == -1)
{ //q2 cinematic - don't load the models.
cl.worldmodel = cl.model_precache[1] = Mod_ForName ("", false);
}
@ -2471,11 +2472,12 @@ void CLQW_ParseServerData (void)
for (j = 0; j < MAX_SPLITS; j++)
{
cl.playernum[j] = cl.allocated_client_slots + j;
cl.playerview[j].playernum = cl.allocated_client_slots + j;
cl.playerview[j].viewentity = 0; //free floating.
for (i = 0; i < UPDATE_BACKUP; i++)
{
cl.inframes[i].playerstate[cl.playernum[j]].pm_type = PM_SPECTATOR;
cl.inframes[i].playerstate[cl.playernum[j]].messagenum = 1;
cl.inframes[i].playerstate[cl.playerview[j].playernum].pm_type = PM_SPECTATOR;
cl.inframes[i].playerstate[cl.playerview[j].playernum].messagenum = 1;
}
}
cl.spectator = true;
@ -2502,9 +2504,10 @@ void CLQW_ParseServerData (void)
Host_EndGame("Server sent us too many alternate clients\n");
for (pnum = 0; pnum < cl.splitclients; pnum++)
{
cl.playernum[pnum] = MSG_ReadByte();
if (cl.playernum[pnum] >= cl.allocated_client_slots)
cl.playerview[pnum].playernum = MSG_ReadByte();
if (cl.playerview[pnum].playernum >= cl.allocated_client_slots)
Host_EndGame("unsupported local player slot\n");
cl.playerview[pnum].viewentity = cl.playerview[pnum].playernum+1;
}
}
else
@ -2515,16 +2518,17 @@ void CLQW_ParseServerData (void)
{
if (clnum == MAX_SPLITS)
Host_EndGame("Server sent us too many alternate clients\n");
cl.playernum[clnum] = pnum;
if (cl.playernum[clnum] & 128)
cl.playerview[clnum].playernum = pnum;
if (cl.playerview[clnum].playernum & 128)
{
cl.spectator = true;
cl.playernum[clnum] &= ~128;
cl.playerview[clnum].playernum &= ~128;
}
if (cl.playernum[clnum] >= cl.allocated_client_slots)
if (cl.playerview[clnum].playernum >= cl.allocated_client_slots)
Host_EndGame("unsupported local player slot\n");
cl.playerview[clnum].viewentity = cl.playerview[clnum].playernum+1;
if (!(cls.fteprotocolextensions & PEXT_SPLITSCREEN))
break;
@ -2553,8 +2557,8 @@ void CLQW_ParseServerData (void)
for (clnum = 0; clnum < cl.splitclients; clnum++)
{
cl.maxspeed[clnum] = maxspeed;
cl.entgravity[clnum] = entgrav;
cl.playerview[clnum].maxspeed = maxspeed;
cl.playerview[clnum].entgravity = entgrav;
}
// seperate the printfs so the server message can have a color
@ -2675,7 +2679,8 @@ void CLQ2_ParseServerData (void)
// parse player entity number
cl.playernum[0] = MSG_ReadShort ();
cl.playerview[0].playernum = MSG_ReadShort ();
cl.playerview[0].viewentity = cl.playerview[0].playernum+1;
cl.splitclients = 1;
cl.spectator = false;
@ -2686,7 +2691,7 @@ void CLQ2_ParseServerData (void)
str = MSG_ReadString ();
Q_strncpyz (cl.levelname, str, sizeof(cl.levelname));
if (cl.playernum[0] == -1)
if (cl.playerview[0].playernum == -1)
{ // playing a cinematic or showing a pic, not a level
SCR_EndLoadingPlaque();
if (!Media_PlayFilm(str, false))
@ -3765,7 +3770,7 @@ void CLQW_ParseStartSoundPacket(void)
}
if (ent == cl.playernum[0]+1)
if (ent == cl.playerview[0].playernum+1)
TP_CheckPickupSound(cl.sound_name[sound_num], pos);
}
@ -3912,7 +3917,7 @@ void CLNQ_ParseStartSoundPacket(void)
S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation, 0, pitchadj);
}
if (ent == cl.playernum[0]+1)
if (ent == cl.playerview[0].playernum+1)
TP_CheckPickupSound(cl.sound_name[sound_num], pos);
}
#endif
@ -4001,12 +4006,12 @@ void CL_NewTranslation (int slot)
{
if (cl.teamplay && cl.spectator)
{
local = Cam_TrackNum(0);
local = Cam_TrackNum(&cl.playerview[0]);
if (local < 0)
local = cl.playernum[0];
local = cl.playerview[0].playernum;
}
else
local = cl.playernum[0];
local = cl.playerview[0].playernum;
if ((cl.teamplay || cls.protocol == CP_NETQUAKE) && !strcmp(player->team, cl.players[local].team))
{
if (cl_teamtopcolor != ~0)
@ -4086,7 +4091,7 @@ void CL_ProcessUserInfo (int slot, player_info_t *player)
player->colourised = TP_FindColours(player->name);
// If it's us
if (slot == cl.playernum[0] && player->name[0])
if (slot == cl.playerview[0].playernum && player->name[0])
{
cl.spectator = player->spectator;
@ -4124,7 +4129,7 @@ void CL_UpdateUserinfo (void)
if (slot == cl.playernum[0] && player->name[0])
if (slot == cl.playerview[0].playernum && player->name[0])
{
char *qz;
qz = Info_ValueForKey(player->userinfo, "Qizmo");
@ -4239,7 +4244,7 @@ void CL_SetStatInt (int pnum, int stat, int value)
cl.players[cls_lastto].stats[stat]=value;
for (pnum = 0; pnum < cl.splitclients; pnum++)
if (spec_track[pnum] == cls_lastto)
if (cl.playerview[pnum].cam_spec_track == cls_lastto)
CL_SetStat_Internal(pnum, stat, value);
}
else
@ -4257,14 +4262,14 @@ void CL_SetStatFloat (int pnum, int stat, float value)
cl.players[cls_lastto].statsf[stat]=value;
for (pnum = 0; pnum < cl.splitclients; pnum++)
if (spec_track[pnum] == cls_lastto)
if (cl.playerview[pnum].cam_spec_track == cls_lastto)
cl.playerview[pnum].statsf[stat] = value;
}
else
cl.playerview[pnum].statsf[stat] = value;
if (stat == STAT_VIEWHEIGHT && cls.z_ext & Z_EXT_VIEWHEIGHT)
cl.viewheight[pnum] = value;
cl.playerview[pnum].viewheight = value;
}
void CL_SetStatString (int pnum, int stat, char *value)
{
@ -4313,7 +4318,7 @@ void CL_MuzzleFlash (int destsplit)
if (!cl_muzzleflash.ival) // remove all muzzleflashes
return;
if (i-1 == cl.playernum[destsplit] && cl_muzzleflash.value == 2)
if (i-1 == cl.playerview[destsplit].playernum && cl_muzzleflash.value == 2)
return;
pack = &cl.inframes[cl.validsequence&UPDATE_MASK].packet_entities;
@ -5396,21 +5401,18 @@ void CLQW_ParseServerMessage (void)
break;
case svc_damage:
V_ParseDamage (destsplit);
V_ParseDamage (&cl.playerview[destsplit]);
break;
case svc_serverdata:
Cbuf_Execute (); // make sure any stuffed commands are done
CLQW_ParseServerData ();
vid.recalc_refdef = true; // leave full screen intermission
break;
#ifdef PEXT_SETVIEW
case svc_setview:
if (!(cls.fteprotocolextensions & PEXT_SETVIEW))
Con_Printf("^1PEXT_SETVIEW is meant to be disabled\n");
cl.viewentity[destsplit]=MSGCL_ReadEntity();
if (cl.viewentity[destsplit] == cl.playernum[destsplit]+1)
cl.viewentity[destsplit] = 0;
cl.playerview[destsplit].viewentity=MSGCL_ReadEntity();
break;
#endif
case svcfte_setangledelta:
@ -5427,12 +5429,13 @@ void CLQW_ParseServerMessage (void)
ang[i] = MSG_ReadAngle();
for (j = 0; j < cl.splitclients; j++)
{
if (Cam_TrackNum(j) == i)
playerview_t *pv = &cl.playerview[j];
if (Cam_TrackNum(pv) == i)
{
cl.playerview[j].fixangle=true;
VectorCopy(ang, cl.playerview[j].simangles);
VectorCopy(ang, cl.playerview[j].viewangles);
VectorCopy(ang, cl.playerview[j].fixangles);
pv->fixangle=true;
VectorCopy(ang, pv->simangles);
VectorCopy(ang, pv->viewangles);
VectorCopy(ang, pv->fixangles);
}
}
break;
@ -5556,11 +5559,14 @@ void CLQW_ParseServerMessage (void)
break;
case svc_killedmonster:
//fixme: update all player stats
cl.playerview[destsplit].stats[STAT_MONSTERS]++;
cl.playerview[destsplit].statsf[STAT_MONSTERS]++;
break;
case svc_foundsecret:
//fixme: update all player stats
cl.playerview[destsplit].stats[STAT_SECRETS]++;
cl.playerview[destsplit].statsf[STAT_SECRETS]++;
break;
case svcqw_updatestatbyte:
@ -5602,7 +5608,6 @@ void CLQW_ParseServerMessage (void)
TP_ExecTrigger ("f_mapend");
cl.intermission = 1;
cl.completed_time = cl.gametime;
vid.recalc_refdef = true; // go to full screen
for (i=0 ; i<3 ; i++)
cl.playerview[destsplit].simorg[i] = MSG_ReadCoord ();
for (i=0 ; i<3 ; i++)
@ -5614,12 +5619,11 @@ void CLQW_ParseServerMessage (void)
case svc_finale:
if (!cl.intermission)
for (i = 0; i < MAX_SPLITS; i++)
cl.playerview[i].simorg[2] += cl.viewheight[i];
cl.playerview[i].simorg[2] += cl.playerview[i].viewheight;
VectorCopy (cl.playerview[destsplit].fixangles, cl.playerview[destsplit].simangles);
cl.intermission = 2;
cl.completed_time = cl.gametime;
vid.recalc_refdef = true; // go to full screen
SCR_CenterPrint (destsplit, MSG_ReadString (), false);
break;
@ -5628,10 +5632,10 @@ void CLQW_ParseServerMessage (void)
break;
case svc_smallkick:
cl.punchangle[destsplit] = -2;
cl.playerview[destsplit].punchangle = -2;
break;
case svc_bigkick:
cl.punchangle[destsplit] = -4;
cl.playerview[destsplit].punchangle = -4;
break;
case svc_muzzleflash:
@ -5699,11 +5703,11 @@ void CLQW_ParseServerMessage (void)
break;
case svc_maxspeed:
cl.maxspeed[destsplit] = MSG_ReadFloat();
cl.playerview[destsplit].maxspeed = MSG_ReadFloat();
break;
case svc_entgravity:
cl.entgravity[destsplit] = MSG_ReadFloat();
cl.playerview[destsplit].entgravity = MSG_ReadFloat();
break;
case svc_setpause:
@ -6086,6 +6090,7 @@ qboolean CLNQ_ParseNQPrints(char *s)
void CLNQ_ParseServerMessage (void)
{
const int destsplit = 0;
int cmd;
char *s;
int i, j;
@ -6227,7 +6232,6 @@ void CLNQ_ParseServerMessage (void)
case svc_serverdata:
Cbuf_Execute (); // make sure any stuffed commands are done
CLNQ_ParseServerData ();
vid.recalc_refdef = true; // leave full screen intermission
break;
case svcdp_precache:
@ -6242,17 +6246,17 @@ void CLNQ_ParseServerMessage (void)
break;
case svc_setview:
if (!cl.viewentity[0])
if (!cl.playerview[destsplit].viewentity)
{
cl.playernum[0] = (cl.viewentity[0] = MSGCL_ReadEntity())-1;
if (cl.playernum[0] >= cl.allocated_client_slots)
cl.playerview[destsplit].playernum = (cl.playerview[destsplit].viewentity = MSGCL_ReadEntity())-1;
if (cl.playerview[destsplit].playernum >= cl.allocated_client_slots)
{
Con_Printf(CON_WARNING "WARNING: Server put us in slot %i. We are not on the scoreboard.\n", cl.playernum[0]);
cl.playernum[0] = cl.allocated_client_slots; //pretend it's an mvd (we have that spare slot)
Con_Printf(CON_WARNING "WARNING: Server put us in slot %i. We are not on the scoreboard.\n", cl.playerview[destsplit].playernum);
cl.playerview[destsplit].playernum = cl.allocated_client_slots; //pretend it's an mvd (we have that spare slot)
}
}
else
cl.viewentity[0]=MSGCL_ReadEntity();
cl.playerview[destsplit].viewentity=MSGCL_ReadEntity();
break;
case svc_signonnum:
@ -6303,9 +6307,10 @@ void CLNQ_ParseServerMessage (void)
break;
case svc_time:
cl.playerview[0].oldfixangle = cl.playerview[0].fixangle;
VectorCopy(cl.playerview[0].fixangles, cl.playerview[0].oldfixangles);
cl.playerview[0].fixangle = false;
//fixme: move this stuff to a common place
cl.playerview[destsplit].oldfixangle = cl.playerview[destsplit].fixangle;
VectorCopy(cl.playerview[destsplit].fixangles, cl.playerview[destsplit].oldfixangles);
cl.playerview[destsplit].fixangle = false;
cls.netchan.outgoing_sequence++;
cls.netchan.incoming_sequence = cls.netchan.outgoing_sequence-1;
@ -6351,6 +6356,7 @@ void CLNQ_ParseServerMessage (void)
strcpy(cl.players[i].name, MSG_ReadString());
if (*cl.players[i].name)
cl.players[i].userid = i+1;
Info_SetValueForKey(cl.players[i].userinfo, "name", cl.players[i].name, sizeof(cl.players[i].userinfo));
}
break;
@ -6377,7 +6383,7 @@ void CLNQ_ParseServerMessage (void)
if (cls.state == ca_active)
Skin_Find (&cl.players[i]);
if (i == cl.playernum[0])
if (i == cl.playerview[destsplit].playernum)
Skin_FlushPlayers();
Sbar_Changed ();
CL_NewTranslation (i);
@ -6410,9 +6416,9 @@ void CLNQ_ParseServerMessage (void)
CL_SetStatFloat (0, i, j);
break;
case svc_setangle:
cl.playerview[0].fixangle=true;
cl.playerview[destsplit].fixangle=true;
for (i=0 ; i<3 ; i++)
cl.playerview[0].viewangles[i] = cl.playerview[0].fixangles[i] = MSG_ReadAngle ();
cl.playerview[destsplit].viewangles[i] = cl.playerview[destsplit].fixangles[i] = MSG_ReadAngle ();
// cl.viewangles[PITCH] = cl.viewangles[ROLL] = 0;
break;
@ -6437,11 +6443,13 @@ void CLNQ_ParseServerMessage (void)
break;
case svc_killedmonster:
cl.playerview[0].stats[STAT_MONSTERS]++;
cl.playerview[destsplit].stats[STAT_MONSTERS]++;
cl.playerview[destsplit].statsf[STAT_MONSTERS]++;
break;
case svc_foundsecret:
cl.playerview[0].stats[STAT_SECRETS]++;
cl.playerview[destsplit].stats[STAT_SECRETS]++;
cl.playerview[destsplit].statsf[STAT_SECRETS]++;
break;
case svc_intermission:
@ -6449,20 +6457,17 @@ void CLNQ_ParseServerMessage (void)
TP_ExecTrigger ("f_mapend");
cl.intermission = 1;
cl.completed_time = cl.gametime;
vid.recalc_refdef = true; // go to full screen
break;
case svc_finale:
cl.intermission = 2;
cl.completed_time = cl.gametime;
vid.recalc_refdef = true; // go to full screen
SCR_CenterPrint (0, MSG_ReadString (), false);
break;
case svc_cutscene:
cl.intermission = 3;
cl.completed_time = cl.gametime;
vid.recalc_refdef = true; // go to full screen
SCR_CenterPrint (0, MSG_ReadString (), false);
break;
@ -6471,7 +6476,7 @@ void CLNQ_ParseServerMessage (void)
break;
case svc_damage:
V_ParseDamage (0);
V_ParseDamage (&cl.playerview[destsplit]);
break;
case svcfitz_skybox:

View File

@ -321,9 +321,10 @@ qintptr_t VARGS Plug_GetPlayerInfo(void *offset, quintptr_t mask, const qintptr_
out = VM_POINTER(arg[1]);
if (out)
{
if (i == -1)
if (i < 0)
{
i = cl.playernum[0];
if (i >= -MAX_SPLITS)
i = cl.playerview[-i-1].playernum;
if (i < 0)
{
memset(out, 0, sizeof(*out));
@ -343,16 +344,16 @@ qintptr_t VARGS Plug_GetPlayerInfo(void *offset, quintptr_t mask, const qintptr_
Q_strncpyz(out->team, cl.players[i].team, sizeof(out->team));
}
pt = Cam_TrackNum(0);
pt = Cam_TrackNum(&cl.playerview[0]);
if (pt < 0)
return (cl.playernum[0] == i);
return (cl.playerview[0].playernum == i);
else
return pt == i;
}
qintptr_t VARGS Plug_LocalPlayerNumber(void *offset, quintptr_t mask, const qintptr_t *arg)
{
return cl.playernum[0];
return cl.playerview[0].playernum;
}
qintptr_t VARGS Plug_GetServerInfo(void *offset, quintptr_t mask, const qintptr_t *arg)
@ -398,6 +399,8 @@ qintptr_t VARGS Plug_Con_SubPrint(void *offset, quintptr_t mask, const qintptr_t
char *name = VM_POINTER(arg[0]);
char *text = VM_POINTER(arg[1]);
console_t *con;
if (!name)
name = "";
if (qrenderer == QR_NONE)
return false;

View File

@ -116,7 +116,7 @@ void CLQ2_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t en
if (!ent->solid)
continue;
if (ent->number == cl.playernum[0]+1)
if (ent->number == cl.playerview[0].playernum+1)
continue;
if (ent->solid == ES_SOLID_BSP)
@ -308,7 +308,7 @@ void CLQ2_PredictMovement (void) //q2 doesn't support split clients.
cl.predicted_step_time = realtime - host_frametime * 0.5;
}
cl.onground[0] = !!(pm.s.pm_flags & Q2PMF_ON_GROUND);
cl.playerview[0].onground = !!(pm.s.pm_flags & Q2PMF_ON_GROUND);
// copy results out for rendering
@ -397,8 +397,8 @@ void CL_PredictUsercmd (int pnum, int entnum, player_state_t *from, player_state
pmove.cmd = *u;
pmove.skipent = entnum;
movevars.entgravity = cl.entgravity[pnum];
movevars.maxspeed = cl.maxspeed[pnum];
movevars.entgravity = cl.playerview[pnum].entgravity;
movevars.maxspeed = cl.playerview[pnum].maxspeed;
movevars.bunnyspeedcap = cl.bunnyspeedcap;
pmove.onladder = false;
@ -427,77 +427,76 @@ void CL_PredictUsercmd (int pnum, int entnum, player_state_t *from, player_state
//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)
void CL_CatagorizePosition (playerview_t *pv)
{
if (cl.spectator)
{
cl.onground[pnum] = false; // in air
pv->onground = false; // in air
return;
}
VectorClear (pmove.velocity);
VectorCopy (cl.playerview[pnum].simorg, pmove.origin);
VectorCopy (pv->simorg, pmove.origin);
pmove.numtouch = 0;
PM_CategorizePosition ();
cl.onground[pnum] = pmove.onground;
pv->onground = 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, float stepchange)
void CL_CalcCrouch (playerview_t *pv, float stepchange)
{
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;
float orgz = DotProduct(pv->simorg, pv->gravitydir); //compensate for running on walls.
VectorSubtract(cl.playerview[pnum].simorg, oldorigin[pnum], delta);
VectorSubtract(pv->simorg, pv->oldorigin, delta);
teleported = Length(delta)>48;
VectorCopy (cl.playerview[pnum].simorg, oldorigin[pnum]);
VectorCopy (pv->simorg, pv->oldorigin);
if (teleported)
{
// possibly teleported or respawned
oldz[pnum] = cl.playerview[pnum].simorg[2];
extracrouch[pnum] = 0;
crouchspeed[pnum] = 100;
cl.crouch[pnum] = 0;
VectorCopy (cl.playerview[pnum].simorg, oldorigin[pnum]);
pv->oldz = orgz;
pv->extracrouch = 0;
pv->crouchspeed = 100;
pv->crouch = 0;
VectorCopy (pv->simorg, pv->oldorigin);
return;
}
if (cl.onground[pnum] && cl.playerview[pnum].simorg[2] - oldz[pnum] > 0)
if (pv->onground && orgz - pv->oldz > 0)
{
if (cl.playerview[pnum].simorg[2] - oldz[pnum] > movevars.stepheight+2)
if (orgz - pv->oldz > movevars.stepheight+2)
{
// if on steep stairs, increase speed
if (crouchspeed[pnum] < 160)
if (pv->crouchspeed < 160)
{
extracrouch[pnum] = cl.playerview[pnum].simorg[2] - oldz[pnum] - host_frametime * 200 - 15;
extracrouch[pnum] = min(extracrouch[pnum], 5);
pv->extracrouch = orgz - pv->oldz - host_frametime * 200 - 15;
pv->extracrouch = min(pv->extracrouch, 5);
}
crouchspeed[pnum] = 160;
pv->crouchspeed = 160;
}
oldz[pnum] += host_frametime * crouchspeed[pnum];
if (oldz[pnum] > cl.playerview[pnum].simorg[2])
oldz[pnum] = cl.playerview[pnum].simorg[2];
pv->oldz += host_frametime * pv->crouchspeed;
if (pv->oldz > orgz)
pv->oldz = orgz;
if (cl.playerview[pnum].simorg[2] - oldz[pnum] > 15 + extracrouch[pnum])
oldz[pnum] = cl.playerview[pnum].simorg[2] - 15 - extracrouch[pnum];
extracrouch[pnum] -= host_frametime * 200;
extracrouch[pnum] = max(extracrouch[pnum], 0);
if (orgz - pv->oldz > 15 + pv->extracrouch)
pv->oldz = orgz - 15 - pv->extracrouch;
pv->extracrouch -= host_frametime * 200;
pv->extracrouch = max(pv->extracrouch, 0);
cl.crouch[pnum] = oldz[pnum] - cl.playerview[pnum].simorg[2];
pv->crouch = pv->oldz - orgz;
}
else
{
// in air or moving down
oldz[pnum] = cl.playerview[pnum].simorg[2];
cl.crouch[pnum] += host_frametime * 150;
if (cl.crouch[pnum] > 0)
cl.crouch[pnum] = 0;
crouchspeed[pnum] = 100;
extracrouch[pnum] = 0;
pv->oldz = orgz;
pv->crouch += host_frametime * 150;
if (pv->crouch > 0)
pv->crouch = 0;
pv->crouchspeed = 100;
pv->extracrouch = 0;
}
}
@ -665,6 +664,8 @@ void CL_CalcClientTime(void)
max = cl.gametime;
min = cl.oldgametime;
if (max < min)
max = min;
if (max)
cl.servertime += host_frametime;
@ -673,14 +674,14 @@ void CL_CalcClientTime(void)
if (cl.servertime > max)
{
if (cl.servertime > cl.gametime)
if (cl.servertime > max)
{
cl.servertime = cl.gametime;
cl.servertime = max;
// Con_Printf("clamped to new time\n");
}
else
{
cl.servertime -= 0.02*(cl.gametime - cl.servertime);
cl.servertime -= 0.02*(max - cl.servertime);
}
}
if (cl.servertime < min)
@ -829,7 +830,7 @@ void CL_PlayerFrameUpdated(player_state_t *plstate, entity_state_t *state, int s
cl.players[state->number-1].statsf[STAT_WEAPONFRAME] = state->u.q1.weaponframe;
for (i = 0; i < cl.splitclients; i++)
{
if (cl.playernum[i] == state->number-1)
if (cl.playerview[i].playernum == state->number-1)
{
cl.playerview[i].stats[STAT_WEAPONFRAME] = state->u.q1.weaponframe;
cl.playerview[i].statsf[STAT_WEAPONFRAME] = state->u.q1.weaponframe;
@ -853,7 +854,7 @@ qboolean CL_PredictPlayer(lerpents_t *le, entity_state_t *state, int sequence)
/*local players just interpolate for now. the prediction code will move it to the right place afterwards*/
for (pnum = 0; pnum < cl.splitclients; pnum++)
{
if (state->number-1 == cl.playernum[pnum])
if (state->number-1 == cl.playerview[pnum].playernum)
return false;
}
@ -886,8 +887,9 @@ qboolean CL_PredictPlayer(lerpents_t *le, entity_state_t *state, int sequence)
CL_PredictMove
==============
*/
void CL_PredictMovePNum (int vnum)
void CL_PredictMovePNum (int seat)
{
playerview_t *pv = &cl.playerview[seat];
inframe_t indstate;
outframe_t indcmd;
int i;
@ -928,14 +930,14 @@ void CL_PredictMovePNum (int vnum)
}
}
cl.nolocalplayer[vnum] = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD);
pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD);
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
{
if (!cl.worldmodel || cl.worldmodel->needload)
return;
cl.crouch[vnum] = 0;
pv->crouch = 0;
CLQ2_PredictMovement();
return;
}
@ -944,12 +946,12 @@ void CL_PredictMovePNum (int vnum)
if (cl_pushlatency.value > 0)
Cvar_Set (&cl_pushlatency, "0");
if (cl.paused && !(cls.demoplayback!=DPB_MVD && cls.demoplayback!=DPB_EZTV) && (!cl.spectator || !autocam[vnum]))
if (cl.paused && !(cls.demoplayback!=DPB_MVD && cls.demoplayback!=DPB_EZTV) && (!cl.spectator || !pv->cam_auto))
return;
if (cl.intermission==1 && cls.protocol == CP_QUAKEWORLD)
{
cl.crouch[vnum] = 0;
pv->crouch = 0;
return;
}
@ -967,7 +969,7 @@ void CL_PredictMovePNum (int vnum)
if (cl.movesequence - cl.ackedmovesequence >= UPDATE_BACKUP-1)
{ //lagging like poo.
if (!cl.intermission) //keep the angles working though.
VectorCopy (cl.playerview[vnum].viewangles, cl.playerview[vnum].simangles);
VectorCopy (pv->viewangles, pv->simangles);
return;
}
@ -977,83 +979,87 @@ void CL_PredictMovePNum (int vnum)
if (!cl.intermission)
{
VectorCopy (cl.playerview[vnum].viewangles, cl.playerview[vnum].simangles);
VectorCopy (pv->viewangles, pv->simangles);
}
vel = from->playerstate[cl.playernum[vnum]].velocity;
org = from->playerstate[cl.playernum[vnum]].origin;
vel = from->playerstate[pv->playernum].velocity;
org = from->playerstate[pv->playernum].origin;
#ifdef PEXT_SETVIEW
if (cl.viewentity[vnum] && (cl.viewentity[vnum] != cl.playernum[vnum]+1 || cl.ackedmovesequence == cl.movesequence))
//if the view is attached to an arbitary entity...
if (pv->viewentity && (pv->viewentity != pv->playernum+1 || cl.ackedmovesequence == cl.movesequence))
{
if (cl.viewentity[vnum] < cl.maxlerpents)
if (pv->viewentity >= 0 && pv->viewentity <= cl.allocated_client_slots && from->playerstate[pv->viewentity-1].messagenum == cl.validsequence)
{
cl.nolocalplayer[vnum] = true;
}
else if (pv->viewentity < cl.maxlerpents)
{
pv->nolocalplayer = true;
// Con_Printf("Using lerped pos\n");
org = cl.lerpents[cl.viewentity[vnum]].origin;
org = cl.lerpents[pv->viewentity].origin;
vel = vec3_origin;
goto fixedorg;
}
}
#endif
if (!from->playerstate[cl.playernum[vnum]].messagenum)
if (!from->playerstate[pv->playernum].messagenum)
{
//no player states?? put the view on an ent
if (cl.playernum[vnum] < cl.maxlerpents)
if (pv->playernum < cl.maxlerpents)
{
cl.nolocalplayer[vnum] = true;
pv->nolocalplayer = true;
// Con_Printf("Using lerped pos\n");
org = cl.lerpents[cl.playernum[vnum]+1].origin;
org = cl.lerpents[pv->playernum+1].origin;
vel = vec3_origin;
goto fixedorg;
}
}
if (((cl_nopred.value && cls.demoplayback!=DPB_MVD && cls.demoplayback != DPB_EZTV)|| cl.playerview[vnum].fixangle || cl.paused))
if (((cl_nopred.value && cls.demoplayback!=DPB_MVD && cls.demoplayback != DPB_EZTV)|| pv->fixangle || cl.paused))
{
if (cl_lerp_players.ival && !cls.demoplayback)
{
lerpents_t *le;
if (cl.nolocalplayer[vnum])
le = &cl.lerpents[spec_track[vnum]+1];
if (pv->nolocalplayer)
le = &cl.lerpents[pv->cam_spec_track+1];
else
le = &cl.lerpplayers[spec_track[vnum]];
le = &cl.lerpplayers[pv->cam_spec_track];
org = le->origin;
vel = vec3_origin;
}
fixedorg:
VectorCopy (vel, cl.playerview[vnum].simvel);
VectorCopy (org, cl.playerview[vnum].simorg);
VectorCopy (vel, pv->simvel);
VectorCopy (org, pv->simorg);
// to = &cl.inframes[cl.ackedinputsequence & UPDATE_MASK];
CL_CatagorizePosition(vnum);
CL_CatagorizePosition(pv);
goto out;
}
// predict forward until cl.time <= to->senttime
oldphysent = pmove.numphysent;
CL_SetSolidPlayers();
pmove.skipent = cl.playernum[vnum]+1;
pmove.skipent = pv->playernum+1;
// Con_Printf("%i<%i %i\n", cl.ackedmovesequence, cl.movesequence, cl.validsequence);
to = &cl.inframes[cl.validsequence & UPDATE_MASK];
cmdto = &cl.outframes[cl.ackedmovesequence & UPDATE_MASK];
if (Cam_TrackNum(vnum)>=0 && CL_MayLerp())
if (pv->viewentity && pv->viewentity != pv->playernum+1 && CL_MayLerp())
{
float f;
if (cl_lerp_players.ival && (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV))
{
lerpents_t *le = &cl.lerpplayers[spec_track[vnum]];
lerpents_t *le = &cl.lerpplayers[pv->cam_spec_track];
org = le->origin;
vel = vec3_origin;
VectorCopy(le->angles, cl.playerview[vnum].simangles);
VectorCopy(le->angles, pv->simangles);
goto fixedorg;
}
@ -1078,19 +1084,19 @@ fixedorg:
// calculate origin
for (i=0 ; i<3 ; i++)
{
lrp[i] = to->playerstate[spec_track[vnum]].origin[i] +
f * (from->playerstate[spec_track[vnum]].origin[i] - to->playerstate[spec_track[vnum]].origin[i]);
lrp[i] = to->playerstate[pv->cam_spec_track].origin[i] +
f * (from->playerstate[pv->cam_spec_track].origin[i] - to->playerstate[pv->cam_spec_track].origin[i]);
lrpv[i] = to->playerstate[spec_track[vnum]].velocity[i] +
f * (from->playerstate[spec_track[vnum]].velocity[i] - to->playerstate[spec_track[vnum]].velocity[i]);
lrpv[i] = to->playerstate[pv->cam_spec_track].velocity[i] +
f * (from->playerstate[pv->cam_spec_track].velocity[i] - to->playerstate[pv->cam_spec_track].velocity[i]);
cl.playerview[vnum].simangles[i] = LerpAngles16(to->playerstate[spec_track[vnum]].command.angles[i], from->playerstate[spec_track[vnum]].command.angles[i], f)*360.0f/65535;
pv->simangles[i] = LerpAngles16(to->playerstate[pv->cam_spec_track].command.angles[i], from->playerstate[pv->cam_spec_track].command.angles[i], f)*360.0f/65535;
}
org = lrp;
vel = lrpv;
cl.pmovetype[vnum] = PM_NONE;
pv->pmovetype = PM_NONE;
goto fixedorg;
}
else
@ -1103,10 +1109,10 @@ fixedorg:
to->playerstate->pm_type = PM_SPECTATOR;
simtime = cmdto->senttime;
VectorCopy (cl.playerview[vnum].simvel, from->playerstate[cl.playernum[vnum]].velocity);
VectorCopy (cl.playerview[vnum].simorg, from->playerstate[cl.playernum[vnum]].origin);
VectorCopy (pv->simvel, from->playerstate[pv->playernum].velocity);
VectorCopy (pv->simorg, from->playerstate[pv->playernum].origin);
CL_PredictUsercmd (vnum, 0, &from->playerstate[cl.playernum[vnum]], &to->playerstate[cl.playernum[vnum]], &cmdto->cmd[vnum]);
CL_PredictUsercmd (seat, 0, &from->playerstate[pv->playernum], &to->playerstate[pv->playernum], &cmdto->cmd[seat]);
}
else
{
@ -1116,7 +1122,7 @@ fixedorg:
to = &cl.inframes[(cl.validsequence+i) & UPDATE_MASK];
cmdto = &cl.outframes[(cl.ackedmovesequence+i) & UPDATE_MASK];
CL_PredictUsercmd (vnum, cl.playernum[vnum]+1, &from->playerstate[cl.playernum[vnum]], &to->playerstate[cl.playernum[vnum]], &cmdto->cmd[vnum]);
CL_PredictUsercmd (seat, pv->playernum+1, &from->playerstate[pv->playernum], &to->playerstate[pv->playernum], &cmdto->cmd[seat]);
if (cmdto->senttime >= simtime)
break;
@ -1132,20 +1138,20 @@ fixedorg:
from = to;
to = &indstate;
cmdto = &indcmd;
if (independantphysics[vnum].msec && !cls.demoplayback)
cmdto->cmd[vnum] = independantphysics[vnum];
if (independantphysics[seat].msec && !cls.demoplayback)
cmdto->cmd[seat] = independantphysics[seat];
else
cmdto->cmd[vnum] = cmdfrom->cmd[vnum];
cmdto->cmd[seat] = cmdfrom->cmd[seat];
cmdto->senttime = simtime;
msec = ((cmdto->senttime - cmdfrom->senttime) * 1000) + 0.5;
cmdto->cmd[vnum].msec = bound(0, msec, 250);
cmdto->cmd[seat].msec = bound(0, msec, 250);
CL_PredictUsercmd (vnum, cl.playernum[vnum]+1, &from->playerstate[cl.playernum[vnum]]
, &to->playerstate[cl.playernum[vnum]], &cmdto->cmd[vnum]);
CL_PredictUsercmd (seat, pv->playernum+1, &from->playerstate[pv->playernum]
, &to->playerstate[pv->playernum], &cmdto->cmd[seat]);
}
cl.onground[vnum] = pmove.onground;
cl.pmovetype[vnum] = to->playerstate[cl.playernum[vnum]].pm_type;
stepheight = to->playerstate[cl.playernum[vnum]].origin[2] - from->playerstate[cl.playernum[vnum]].origin[2];
pv->onground = pmove.onground;
pv->pmovetype = to->playerstate[pv->playernum].pm_type;
stepheight = to->playerstate[pv->playernum].origin[2] - from->playerstate[pv->playernum].origin[2];
}
//backdate it if our simulation time is in the past. this will happen on localhost, but not on 300-ping servers.
@ -1162,12 +1168,12 @@ fixedorg:
// Con_Printf("%f %f %f\n", cmdfrom->senttime, simtime, cmdto->senttime);
if (cmdto->senttime == cmdfrom->senttime)
{
VectorCopy (to->playerstate[cl.playernum[vnum]].velocity, cl.playerview[vnum].simvel);
VectorCopy (to->playerstate[cl.playernum[vnum]].origin, cl.playerview[vnum].simorg);
VectorCopy (to->playerstate[pv->playernum].velocity, pv->simvel);
VectorCopy (to->playerstate[pv->playernum].origin, pv->simorg);
}
else
{
int pnum = cl.playernum[vnum];
int pnum = pv->playernum;
// now interpolate some fraction of the final frame
f = (simtime - cmdfrom->senttime) / (cmdto->senttime - cmdfrom->senttime);
@ -1179,40 +1185,40 @@ fixedorg:
for (i=0 ; i<3 ; i++)
if ( fabs(from->playerstate[pnum].origin[i] - to->playerstate[pnum].origin[i]) > 128)
{ // teleported, so don't lerp
VectorCopy (to->playerstate[pnum].velocity, cl.playerview[vnum].simvel);
VectorCopy (to->playerstate[pnum].origin, cl.playerview[vnum].simorg);
VectorCopy (to->playerstate[pnum].velocity, pv->simvel);
VectorCopy (to->playerstate[pnum].origin, pv->simorg);
goto out;
}
for (i=0 ; i<3 ; i++)
{
cl.playerview[vnum].simorg[i] = (1-f)*from->playerstate[pnum].origin[i] + f*to->playerstate[pnum].origin[i];
cl.playerview[vnum].simvel[i] = (1-f)*from->playerstate[pnum].velocity[i] + f*to->playerstate[pnum].velocity[i];
pv->simorg[i] = (1-f)*from->playerstate[pnum].origin[i] + f*to->playerstate[pnum].origin[i];
pv->simvel[i] = (1-f)*from->playerstate[pnum].velocity[i] + f*to->playerstate[pnum].velocity[i];
/* if (cl.spectator && Cam_TrackNum(vnum) >= 0)
cl.playerview[vnum].simangles[i] = LerpAngles16(from->playerstate[pnum].command.angles[i], to->playerstate[pnum].command.angles[i], f) * (360.0/65535);
pv->simangles[i] = LerpAngles16(from->playerstate[pnum].command.angles[i], to->playerstate[pnum].command.angles[i], f) * (360.0/65535);
else if (cls.demoplayback == DPB_QUAKEWORLD)
cl.playerview[vnum].simangles[i] = LerpAngles16(cmdfrom->cmd[vnum].angles[i], cmdto->cmd[vnum].angles[i], f) * (360.0/65535);
pv->simangles[i] = LerpAngles16(cmdfrom->cmd[vnum].angles[i], cmdto->cmd[vnum].angles[i], f) * (360.0/65535);
*/ }
CL_CatagorizePosition(vnum);
CL_CatagorizePosition(pv);
}
if (cl.nolocalplayer[vnum] && cl.maxlerpents > cl.playernum[vnum]+1)
if (pv->nolocalplayer && cl.maxlerpents > pv->playernum+1)
{
//keep the entity tracking the prediction position, so mirrors don't go all weird
VectorCopy(to->playerstate[cl.playernum[vnum]].origin, cl.lerpents[cl.playernum[vnum]+1].origin);
VectorScale(cmdto->cmd[vnum].angles, 360.0f / 0xffff, cl.lerpents[cl.playernum[vnum]+1].angles);
cl.lerpents[cl.playernum[vnum]+1].angles[0] *= -0.333;
VectorCopy(to->playerstate[pv->playernum].origin, cl.lerpents[pv->playernum+1].origin);
VectorScale(pv->simangles, 1, cl.lerpents[pv->playernum+1].angles);
cl.lerpents[pv->playernum+1].angles[0] *= -0.333;
}
if (cls.demoplayback)
CL_LerpMove (vnum, cmdto->senttime);
CL_LerpMove (seat, cmdto->senttime);
out:
CL_CalcCrouch (vnum, stepheight);
cl.waterlevel[vnum] = pmove.waterlevel;
VectorCopy(pmove.gravitydir, cl.playerview[vnum].gravitydir);
CL_CalcCrouch (pv, stepheight);
pv->waterlevel = pmove.waterlevel;
VectorCopy(pmove.gravitydir, pv->gravitydir);
}
void CL_PredictMove (void)

View File

@ -918,8 +918,6 @@ void SCR_Fov_Callback (struct cvar_s *var, char *oldvalue)
Cvar_ForceSet (var, "170");
return;
}
vid.recalc_refdef = true;
}
void SCR_Viewsize_Callback (struct cvar_s *var, char *oldvalue)
@ -934,130 +932,13 @@ void SCR_Viewsize_Callback (struct cvar_s *var, char *oldvalue)
Cvar_ForceSet (var, "120");
return;
}
vid.recalc_refdef = true;
}
void CL_Sbar_Callback(struct cvar_s *var, char *oldvalue)
{
vid.recalc_refdef = true;
}
/*
=================
SCR_CalcRefdef
Must be called whenever vid changes
Internal use only
=================
*/
void SCR_CalcRefdef (void)
{
float size;
int h;
qboolean full = false;
vid.recalc_refdef = 0;
// force the status bar to redraw
Sbar_Changed ();
//========================================
r_refdef.flags = 0;
// intermission is always full screen
if (cl.intermission)
size = 120;
else
size = scr_viewsize.value;
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2) //q2 never has a hud.
sb_lines = 0;
else
#endif
if (size >= 120)
sb_lines = 0; // no status bar at all
else if (size >= 110)
sb_lines = 24; // no inventory
else
sb_lines = 24+16+8;
if (scr_viewsize.value >= 100.0 || scr_chatmode)
{
full = true;
size = 100.0;
}
else
size = scr_viewsize.value;
if (cl.intermission)
{
full = true;
size = 100.0;
sb_lines = 0;
}
size /= 100.0;
if (cl_sbar.value!=1 && full)
h = vid.height;
else
h = vid.height - sb_lines;
r_refdef.vrect.width = vid.width * size;
if (r_refdef.vrect.width < 96)
{
size = 96.0 / r_refdef.vrect.width;
r_refdef.vrect.width = 96; // min for icons
}
r_refdef.vrect.height = vid.height * size;
if (cl_sbar.value==1 || !full)
{
if (r_refdef.vrect.height > vid.height - sb_lines)
r_refdef.vrect.height = vid.height - sb_lines;
}
else if (r_refdef.vrect.height > vid.height)
r_refdef.vrect.height = vid.height;
r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
if (full)
r_refdef.vrect.y = 0;
else
r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
if (scr_chatmode)
{
if (scr_chatmode != 2)
r_refdef.vrect.height= r_refdef.vrect.y=vid.height/2;
r_refdef.vrect.width = r_refdef.vrect.x=vid.width/2;
if (r_refdef.vrect.width<320 || r_refdef.vrect.height<200) //disable hud if too small
sb_lines=0;
}
r_refdef.fov_x = scr_fov.value;
if (cl.playerview[r_refdef.currentplayernum].stats[STAT_VIEWZOOM])
r_refdef.fov_x *= cl.playerview[r_refdef.currentplayernum].stats[STAT_VIEWZOOM]/255.0f;
if (r_refdef.fov_x < 1)
r_refdef.fov_x = 1;
else if (r_refdef.fov_x > 170)
r_refdef.fov_x = 170;
r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
// r_refdef.vrect.height/=2;
scr_vrect = r_refdef.vrect;
}
void SCR_CrosshairPosition(int pnum, int *x, int *y)
void SCR_CrosshairPosition(playerview_t *pview, int *x, int *y)
{
extern cvar_t cl_crossx, cl_crossy, crosshaircorrect, v_viewheight;
@ -1072,9 +953,9 @@ void SCR_CrosshairPosition(int pnum, int *x, int *y)
vec3_t start;
vec3_t right, up, fwds;
AngleVectors(cl.playerview[pnum].simangles, fwds, right, up);
AngleVectors(pview->simangles, fwds, right, up);
VectorCopy(cl.playerview[pnum].simorg, start);
VectorCopy(pview->simorg, start);
start[2]+=16;
VectorMA(start, 100000, fwds, end);
@ -1090,7 +971,7 @@ void SCR_CrosshairPosition(int pnum, int *x, int *y)
}
else
{
adj=cl.viewheight[pnum];
adj=pview->viewheight;
if (v_viewheight.value < -7)
adj+=-7;
else if (v_viewheight.value > 4)
@ -1099,7 +980,7 @@ void SCR_CrosshairPosition(int pnum, int *x, int *y)
adj+=v_viewheight.value;
start[2]+=adj;
Matrix4x4_CM_Project(tr.endpos, end, cl.playerview[pnum].simangles, start, r_refdef.fov_x, r_refdef.fov_y);
Matrix4x4_CM_Project(tr.endpos, end, pview->simangles, start, r_refdef.fov_x, r_refdef.fov_y);
*x = rect.x+rect.width*end[0];
*y = rect.y+rect.height*(1-end[1]);
return;
@ -1356,7 +1237,7 @@ void SCR_DrawUPS (void)
if ((t - lastupstime) >= 1.0/20)
{
if (cl.spectator)
track = Cam_TrackNum(0);
track = Cam_TrackNum(&cl.playerview[0]);
else
track = -1;
if (track != -1)
@ -1772,7 +1653,12 @@ void SCR_SetUpToDrawConsole (void)
}
else if ((key_dest == key_console || key_dest == key_game) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false))
{
if (cls.state < ca_demostart)
#ifdef VM_UI
if (key_dest == key_game && (UI_MenuState() || UI_OpenMenu()))
;
else
#endif
if (cls.state < ca_demostart)
key_dest = key_console;
scr_con_current = scr_conlines = vid.height * fullscreenpercent;
}
@ -2235,64 +2121,26 @@ void SCR_BringDownConsole (void)
void SCR_TileClear (void)
{
#ifdef PLUGINS
// extern cvar_t plug_sbar;
#endif
if (cl.splitclients>1)
return; //splitclients always takes the entire screen.
/*#ifdef PLUGINS
if (plug_sbar.ival)
if (r_refdef.vrect.width < r_refdef.grect.width)
{
if (scr_vrect.x > 0)
{
// left
R2D_TileClear (0, 0, scr_vrect.x, vid.height);
// right
R2D_TileClear (scr_vrect.x + scr_vrect.width, 0,
vid.width - scr_vrect.x + scr_vrect.width,
vid.height);
}
if (scr_vrect.y > 0 || scr_vrect.height != vid.height)
{
// top
R2D_TileClear (scr_vrect.x, 0,
scr_vrect.width,
scr_vrect.y);
// bottom
R2D_TileClear (scr_vrect.x,
scr_vrect.y + scr_vrect.height,
scr_vrect.width,
vid.height);
}
int w;
// left
R2D_TileClear (r_refdef.grect.x, r_refdef.grect.y, r_refdef.vrect.x-r_refdef.grect.x, r_refdef.grect.height - sb_lines);
// right
w = (r_refdef.grect.x+r_refdef.grect.width) - (r_refdef.vrect.x+r_refdef.vrect.width);
R2D_TileClear ((r_refdef.grect.x+r_refdef.grect.width) - (w), r_refdef.grect.y, w, r_refdef.grect.height - sb_lines);
}
else
#endif
*/
if (r_refdef.vrect.height < r_refdef.grect.height)
{
if (scr_vrect.x > 0)
{
// left
R2D_TileClear (0, 0, scr_vrect.x, vid.height - sb_lines);
// right
R2D_TileClear (scr_vrect.x + scr_vrect.width, 0,
vid.width - scr_vrect.x + scr_vrect.width,
vid.height - sb_lines);
}
if (scr_vrect.y > 0)
{
// top
R2D_TileClear (scr_vrect.x, 0,
scr_vrect.width,
scr_vrect.y);
// bottom
R2D_TileClear (scr_vrect.x,
scr_vrect.y + scr_vrect.height,
scr_vrect.width,
vid.height - cl_sbar.value?sb_lines:0 -
(scr_vrect.height + scr_vrect.y));
}
// top
R2D_TileClear (r_refdef.vrect.x, r_refdef.grect.y,
r_refdef.vrect.width,
r_refdef.vrect.y - r_refdef.grect.y);
// bottom
R2D_TileClear (r_refdef.vrect.x,
r_refdef.vrect.y + r_refdef.vrect.height,
r_refdef.vrect.width,
(r_refdef.grect.y+r_refdef.grect.height) - sb_lines - (r_refdef.vrect.y + r_refdef.vrect.height));
}
}
@ -2303,6 +2151,8 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
{
RSpeedMark();
R2D_ImageColours(1, 1, 1, 1);
//
// draw any areas not covered by the refresh
//
@ -2313,18 +2163,6 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
{
SCR_DrawLoading();
if (!nohud)
{
#ifdef PLUGINS
Plug_SBar ();
#else
if (Sbar_ShouldDraw())
{
Sbar_Draw ();
Sbar_DrawScoreboard ();
}
#endif
}
SCR_ShowPics_Draw();
}
else if (cl.intermission == 1)
@ -2352,15 +2190,6 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
SCR_DrawGameClock();
SCR_DrawTurtle ();
SCR_DrawPause ();
#ifdef PLUGINS
Plug_SBar ();
#else
if (Sbar_ShouldDraw())
{
Sbar_Draw ();
Sbar_DrawScoreboard ();
}
#endif
SCR_ShowPics_Draw();
CL_DrawPrydonCursor();

View File

@ -721,7 +721,8 @@ void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ n
{
for (i = 0; i < cl.splitclients; i++)
{
if (ent == (autocam[i]?(spec_track[i]+1):(cl.playernum[i]+1)))
playerview_t *pv = &cl.playerview[i];
if (ent == (pv->cam_auto?(pv->cam_spec_track+1):(pv->playernum+1)))
{
VectorCopy(end, playerbeam_end[i]);
break;
@ -3102,7 +3103,8 @@ void CL_UpdateBeams (void)
{
for (j = 0; j < cl.splitclients; j++)
{
if (b->entity == ((cl.spectator&&autocam[j])?spec_track[j]+1:(cl.playernum[j]+1)))
playerview_t *pv = &cl.playerview[j];
if (b->entity == ((cl.spectator&&pv->cam_auto)?pv->cam_spec_track+1:(pv->playernum+1)))
{
player_state_t *pl;
// VectorSubtract(cl.simorg, b->start, org);
@ -3114,24 +3116,24 @@ void CL_UpdateBeams (void)
vec3_t fwd, org, ang;
float delta, f, len;
if (cl.spectator && autocam[j])
if (cl.spectator && pv->cam_auto)
{ //if we're tracking someone, use their origin explicitly.
vieworg = pl->origin;
}
else
vieworg = cl.playerview[j].simorg;
viewang = cl.playerview[j].simangles;
vieworg = pv->simorg;
viewang = pv->simangles;
if (cl_truelightning.ival >= 2 && cls.netchan.outgoing_sequence > cl_truelightning.ival)
{
inframe_t *frame = &cl.inframes[(cls.netchan.outgoing_sequence-cl_truelightning.ival)&UPDATE_MASK];
viewang = frame->playerstate[cl.playernum[j]].viewangles;
viewang[0] = (frame->playerstate[cl.playernum[j]].command.angles[0] * 360) / 65336.0;
viewang[1] = (frame->playerstate[cl.playernum[j]].command.angles[1] * 360) / 65336.0;
viewang = frame->playerstate[pv->playernum].viewangles;
viewang[0] = (frame->playerstate[pv->playernum].command.angles[0] * 360) / 65336.0;
viewang[1] = (frame->playerstate[pv->playernum].command.angles[1] * 360) / 65336.0;
}
VectorCopy (vieworg, b->start);
b->start[2] += cl.crouch[j] + bound(-7, v_viewheight.value, 4);
b->start[2] += pv->crouch + bound(-7, v_viewheight.value, 4);
f = bound(0, cl_truelightning.value, 1);

View File

@ -341,6 +341,19 @@ struct q3polyvert_s
#define MAX_VMQ3_CACHED_STRINGS 1024
char *stringcache[1024];
void VMQ3_FlushStringHandles(void)
{
int i;
for (i = 0; i < MAX_VMQ3_CACHED_STRINGS; i++)
{
if (stringcache[i])
{
Z_Free(stringcache[i]);
stringcache[i] = NULL;
}
}
}
char *VMQ3_StringFromHandle(int handle)
{
if (!handle)
@ -406,7 +419,7 @@ void VQ3_AddEntity(const q3refEntity_t *q3)
if (q3->renderfx & Q3RF_DEPTHHACK)
ent.flags |= Q2RF_DEPTHHACK;
if (q3->renderfx & Q3RF_THIRD_PERSON)
ent.externalmodelview = ~0;
ent.flags |= Q2RF_EXTERNALMODEL;
if (q3->renderfx & Q3RF_NOSHADOW)
ent.flags |= RF_NOSHADOW;
@ -491,7 +504,7 @@ int VM_LerpTag(void *out, model_t *model, int f1, int f2, float l2, char *tagnam
tagnum = Mod_TagNumForName(model, tagname);
found = Mod_GetTag(model, tagnum, &fstate, tr);
if (found)
if (found && tagnum)
{
ang[0] = tr[0];
ang[1] = tr[1];
@ -575,7 +588,7 @@ void VQ3_RenderView(const q3refdef_t *ref)
r_refdef.vrect.height = ref->height;
r_refdef.time = ref->time/1000.0f;
r_refdef.useperspective = true;
r_refdef.currentplayernum = -1;
r_refdef.playerview = &cl.playerview[0];
if (r_torch.ival)
{
@ -590,6 +603,7 @@ void VQ3_RenderView(const q3refdef_t *ref)
memcpy(cl.q2frame.areabits, ref->areamask, sizeof(cl.q2frame.areabits));
R_RenderView();
r_refdef.playerview = NULL;
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL)
{
@ -597,7 +611,6 @@ void VQ3_RenderView(const q3refdef_t *ref)
}
#endif
vid.recalc_refdef = 1;
r_refdef.time = 0;
}

View File

@ -493,6 +493,93 @@ typedef struct {
int sequence; /*so csqc code knows that the ent is still valid*/
entity_state_t *entstate;
} lerpents_t;
//state associated with each player 'seat' (one for each splitscreen client)
//note that this doesn't include networking inputlog info.
struct playerview_s
{
int playernum; //cl.players index for this player.
qboolean nolocalplayer; //inhibit use of qw-style players, predict based on entities.
#ifdef PEXT_SETVIEW
int viewentity; //view is attached to this entity.
#endif
// information for local display
int stats[MAX_CL_STATS]; // health, etc
float statsf[MAX_CL_STATS]; // health, etc
char *statsstr[MAX_CL_STATS]; // health, etc
float item_gettime[32]; // cl.time of aquiring item, for blinking
float faceanimtime; // use anim frame if cl.time < this
int sb_hexen2_cur_item;//hexen2 hud
float sb_hexen2_item_time;
qboolean sb_hexen2_extra_info;//show the extra stuff
qboolean sb_hexen2_infoplaque;
// 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;
vec3_t viewanglechange;
vec3_t gravitydir;
// pitch drifting vars
float pitchvel;
qboolean nodrift;
float driftmove;
double laststop;
//prediction state
int pmovetype;
float entgravity;
float maxspeed;
vec3_t simorg;
vec3_t simvel;
vec3_t simangles;
float rollangle;
float crouch; // local amount for smoothing stepups
vec3_t oldorigin; // to track step smoothing
float oldz, extracrouch, crouchspeed; // to track step smoothing
qboolean onground;
float viewheight;
int waterlevel; //for smartjump
float punchangle; // temporary view kick from weapon firing
qboolean fixangle; //received a fixangle - so disable prediction till the next packet.
qboolean oldfixangle; //received a fixangle - so disable prediction till the next packet.
vec3_t fixangles; //received a fixangle - so disable prediction till the next packet.
vec3_t oldfixangles; //received a fixangle - so disable prediction till the next packet.
float v_dmg_time; //various view knockbacks.
float v_dmg_roll;
float v_dmg_pitch;
double bobtime; //sine wave
double bobcltime; //for tracking time increments
float bob; //bob height
vec3_t cam_desired_position; // where the camera wants to be
qboolean cam_locked; //
int cam_oldbuttons; //
vec3_t cam_viewangles; //
double cam_lastviewtime; //
int cam_spec_track; // player# of who we are tracking
enum
{
CAM_NONE = 0,
CAM_TRACK = 1
} cam_auto; //
entity_t viewent; // is this not utterly redundant yet?
struct model_s *oldmodel;
float lerptime;
float frameduration;
int prevframe;
int oldframe;
};
//
// the client_state_t structure is wiped completely at every
// server signon
@ -546,60 +633,10 @@ typedef struct
//when running splitscreen, we have multiple viewports all active at once
int splitclients; //we are running this many clients split screen.
struct playerview_s
{
// information for local display
int stats[MAX_CL_STATS]; // health, etc
float statsf[MAX_CL_STATS]; // health, etc
char *statsstr[MAX_CL_STATS]; // health, etc
float item_gettime[32]; // cl.time of aquiring item, for blinking
float faceanimtime; // use anim frame if cl.time < this
// 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;
vec3_t viewanglechange;
vec3_t gravitydir;
// pitch drifting vars
float pitchvel;
qboolean nodrift;
float driftmove;
double laststop;
vec3_t simorg;
vec3_t simvel;
vec3_t simangles;
float rollangle;
qboolean fixangle; //received a fixangle - so disable prediction till the next packet.
qboolean oldfixangle; //received a fixangle - so disable prediction till the next packet.
vec3_t fixangles; //received a fixangle - so disable prediction till the next packet.
vec3_t oldfixangles; //received a fixangle - so disable prediction till the next packet.
} playerview[MAX_SPLITS];
float crouch[MAX_SPLITS]; // local amount for smoothing stepups
qboolean onground[MAX_SPLITS];
float viewheight[MAX_SPLITS];
entity_t viewent[MAX_SPLITS]; // weapon model
float punchangle[MAX_SPLITS]; // temporary view kick from weapon firing
int playernum[MAX_SPLITS];
qboolean nolocalplayer[MAX_SPLITS];
#ifdef PEXT_SETVIEW
int viewentity[MAX_SPLITS];
#endif
int waterlevel[MAX_SPLITS]; //for smartjump
playerview_t playerview[MAX_SPLITS];
// localized movement vars
float entgravity[MAX_SPLITS];
float maxspeed[MAX_SPLITS];
float bunnyspeedcap;
int pmovetype[MAX_SPLITS];
// the client simulates or interpolates movement to get these values
double time; // this is the time value that the client
@ -835,8 +872,8 @@ void CL_SetInfo (int pnum, char *key, char *value);
void CL_BeginServerConnect(int port);
char *CL_TryingToConnect(void);
void CL_ExecInitialConfigs(void);
qboolean CL_CheckBootDownloads(void);
void CL_ExecInitialConfigs(char *defaultexec);
ftemanifest_t *CL_Manifest_Parse(vfsfile_t *file, const char *defaultsourceurl);
extern int cl_numvisedicts;
extern int cl_maxvisedicts;
@ -1005,19 +1042,21 @@ qboolean CL_CheckBaselines (int size);
//
// view.c
//
void V_StartPitchDrift (int pnum);
void V_StopPitchDrift (int pnum);
void V_StartPitchDrift (playerview_t *pv);
void V_StopPitchDrift (playerview_t *pv);
void V_RenderView (void);
void V_Register (void);
void V_ParseDamage (int pnum);
void V_ParseDamage (playerview_t *pv);
void V_SetContentsColor (int contents);
//used directly by csqc
void V_CalcRefdef (int pnum);
void V_CalcGunPositionAngle (int pnum, float bob);
float V_CalcBob (int pnum, qboolean queryold);
void DropPunchAngle (int pnum);
void V_CalcRefdef (playerview_t *pv);
void V_ClearRefdef(playerview_t *pv);
void V_ApplyRefdef(void);
void V_CalcGunPositionAngle (playerview_t *pv, float bob);
float V_CalcBob (playerview_t *pv, qboolean queryold);
void DropPunchAngle (playerview_t *pv);
//
@ -1060,6 +1099,7 @@ void CL_ParsePlayerinfo (void);
void CL_ParseClientPersist(void);
//these last ones are needed for csqc handling of engine-bound ents.
void CL_ClearEntityLists(void);
void CL_EditExternalModels(int newviewentity);
void CL_FreeVisEdicts(void);
void CL_LinkViewModel(void);
void CL_LinkPlayers (void);
@ -1142,25 +1182,19 @@ void CL_CalcClientTime(void);
//
// 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);
int Cam_TrackNum(int pnum);
void Cam_Unlock(int pnum);
void Cam_Lock(int pnum, int playernum);
void Cam_SelfTrack(int pnum);
void Cam_Track(int pnum, usercmd_t *cmd);
void Cam_TrackCrosshairedPlayer(int pnum);
qboolean Cam_DrawViewModel(playerview_t *pv);
qboolean Cam_DrawEntity(playerview_t *pv, int entitykey);
int Cam_TrackNum(playerview_t *pv);
void Cam_Unlock(playerview_t *pv);
void Cam_Lock(playerview_t *pv, int playernum);
void Cam_SelfTrack(playerview_t *pv);
void Cam_Track(playerview_t *pv, usercmd_t *cmd);
void Cam_TrackCrosshairedPlayer(playerview_t *pv);
void Cam_SetAutoTrack(int userid);
void Cam_FinishMove(int pnum, usercmd_t *cmd);
void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd);
void Cam_Reset(void);
void Cam_TrackPlayer(int pnum, char *cmdname, char *plrarg);
void Cam_Lock(int pnum, int playernum);
void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg);
void Cam_Lock(playerview_t *pv, int playernum);
void CL_InitCam(void);
void QDECL vectoangles(vec3_t fwd, vec3_t ang);

View File

@ -1015,7 +1015,7 @@ void CLQ2_ParseFrame (void)
i = MSG_ReadByte ();
for (j=0 ; j<i ; j++)
cl.inframes[ (cls.netchan.incoming_acknowledged-1-j)&UPDATE_MASK ].receivedtime = -2;
cl.inframes[ (cls.netchan.incoming_acknowledged-1-j)&UPDATE_MASK ].latency = -2;
if (cl_shownet.value == 3)
Con_Printf (" frame:%i delta:%i\n", cl.q2frame.serverframe, cl.q2frame.deltaframe);
@ -1359,9 +1359,6 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
else
ent.flags = renderfx;
if (renderfx & Q2RF_EXTERNALMODEL)
ent.externalmodelview = ~0;
// calculate angles
if (effects & Q2EF_ROTATE)
{ // some bonus items auto-rotate
@ -1398,11 +1395,11 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
ent.angles[0]*=-1; //q2 has it fixed.
if (s1->number == cl.playernum[0]+1) //woo! this is us!
if (s1->number == cl.playerview[pnum].playernum+1) //woo! this is us!
{
// VectorCopy(cl.predicted_origin, ent.origin);
// VectorCopy(cl.predicted_origin, ent.oldorigin);
// ent.flags |= Q2RF_EXTERNALMODEL; // only draw from mirrors
ent.flags |= Q2RF_EXTERNALMODEL; // only draw from mirrors
if (effects & Q2EF_FLAG1)
V_AddLight (ent.keynum, ent.origin, 225, 0.2, 0.05, 0.05);
@ -1508,7 +1505,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
// ent.skin = NULL; // never use a custom skin on others
ent.skinnum = 0;
ent.flags = 0;
ent.flags &= Q2RF_EXTERNALMODEL;
ent.shaderRGBAf[3] = 1;
// duplicate for linked models
@ -1763,7 +1760,7 @@ void CLQ2_AddViewWeapon (q2player_state_t *ps, q2player_state_t *ops)
return;
//generate root matrix..
view = &cl.viewent[0];
view = &cl.playerview[0].viewent;
VectorCopy(cl.playerview[0].simorg, view->origin);
AngleVectors(cl.playerview[0].simangles, view->axis[0], view->axis[1], view->axis[2]);
VectorInverse(view->axis[1]);
@ -1829,8 +1826,6 @@ void CLQ2_CalcViewValues (void)
r_refdef.useperspective = true;
r_refdef.currentplayernum = 0;
// find the previous frame to interpolate from
ps = &cl.q2frame.playerstate;
i = (cl.q2frame.serverframe - 1) & Q2UPDATE_MASK;
@ -1919,10 +1914,6 @@ void CLQ2_AddEntities (void)
if (cls.state != ca_active)
return;
r_refdef.currentplayernum = 0;
if (cl.time*1000 > cl.q2frame.servertime)
{
// if (cl_showclamp.value)

View File

@ -492,7 +492,8 @@ qboolean CLQ3_SystemInfoChanged(char *str)
VFS_CLOSE(f);
continue;
}
FS_GenCachedPakName(va("%s.pk3", com_token), crc, cls.downloadlocalname, sizeof(cls.downloadlocalname));
if (!FS_GenCachedPakName(va("%s.pk3", com_token), crc, cls.downloadlocalname, sizeof(cls.downloadlocalname)))
continue;
f = FS_OpenVFS(cls.downloadlocalname, "rb", FS_ROOT);
if (f)
{
@ -500,12 +501,14 @@ qboolean CLQ3_SystemInfoChanged(char *str)
continue;
}
if (!FS_GenCachedPakName(va("%s.tmp", com_token), crc, cls.downloadtempname, sizeof(cls.downloadtempname)))
continue;
//fixme: request to download it
Con_Printf("Sending request to download %s\n", com_token);
CLQ3_SendClientCommand("download %s.pk3", com_token);
ccs.downloadchunknum = 0;
//q3's downloads are relative to root, but they do at least force a pk3 extension.
FS_GenCachedPakName(va("%s.tmp", com_token), crc, cls.downloadtempname, sizeof(cls.downloadtempname));
snprintf(cls.downloadremotename, sizeof(cls.downloadremotename), "%s.pk3", com_token);
cls.downloadmethod = DL_Q3;
cls.downloadpercent = 0;
@ -514,11 +517,11 @@ qboolean CLQ3_SystemInfoChanged(char *str)
pc = Info_ValueForKey(str, "sv_paks"); //the ones that we are allowed to use (in order!)
pn = Info_ValueForKey(str, "sv_pakNames");
FS_ForceToPure(pn, pc, ccs.fs_key);
FS_PureMode(2, pn, pc, ccs.fs_key);
}
else
{
FS_ForceToPure(NULL, NULL, ccs.fs_key);
FS_PureMode(0, NULL, NULL, ccs.fs_key);
}
return true; //yay, we're in
@ -586,7 +589,7 @@ void CLQ3_ParseGameState(void)
}
}
cl.playernum[0] = MSG_ReadLong();
cl.playerview[0].playernum = MSG_ReadLong();
ccs.fs_key = MSG_ReadLong();
if (!CLQ3_SystemInfoChanged(CG_GetConfigString(CFGSTR_SYSINFO)))
@ -916,13 +919,13 @@ void CLQ3_SendCmd(usercmd_t *cmd)
if (key_dest != key_game || (keycatcher&3))
cmd->buttons |= 2; //add in the 'at console' button
cl.outframes[ccs.currentUserCmdNumber&CMD_MASK].cmd[0] = *cmd;
ccs.currentUserCmdNumber++;
cl.outframes[cl.movesequence&Q3UPDATE_MASK].cmd[0] = *cmd;
cl.movesequence++;
frame = &cl.outframes[cls.netchan.outgoing_sequence & Q3UPDATE_MASK];
frame->cmd_sequence = ccs.currentUserCmdNumber;
frame->cmd_sequence = cl.movesequence;
frame->server_message_num = ccs.serverMessageNum;
frame->server_time = cl.gametime;
frame->client_time = Sys_DoubleTime()*1000;
@ -950,7 +953,7 @@ void CLQ3_SendCmd(usercmd_t *cmd)
i = (cls.netchan.outgoing_sequence - 1);
oldframe = &cl.outframes[i & Q3UPDATE_MASK];
cmdcount = ccs.currentUserCmdNumber - oldframe->cmd_sequence;
cmdcount = cl.movesequence - oldframe->cmd_sequence;
if (cmdcount > Q3UPDATE_MASK)
cmdcount = Q3UPDATE_MASK;
// begin a client move command, if any
@ -973,7 +976,7 @@ void CLQ3_SendCmd(usercmd_t *cmd)
// send this and the previous cmds in the message, so
// if the last packet was dropped, it can be recovered
from = &nullcmd;
for (i = oldframe->cmd_sequence; i < ccs.currentUserCmdNumber; i++)
for (i = oldframe->cmd_sequence; i < cl.movesequence; i++)
{
to = &cl.outframes[i&CMD_MASK].cmd[0];
MSG_Q3_WriteDeltaUsercmd( &msg, key, from, to );

View File

@ -222,7 +222,6 @@ typedef struct {
int lastServerCommandNum;
int currentServerCommandNum;
int numClientCommands;
int currentUserCmdNumber;
int serverMessageNum;
int serverTime;

View File

@ -123,8 +123,8 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
p2 = tmp;
}
u1 = (p1 == (cl.playernum[0]&127));
u2 = (p2 == (cl.playernum[0]&127));
u1 = (p1 == (cl.playerview[0].playernum));
u2 = (p2 == (cl.playerview[0].playernum));
switch(mt)
{

View File

@ -376,11 +376,22 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
}
#ifdef PEXT_CSQC
if (mx || my)
if (CSQC_MouseMove(mx, my, mouse->qdeviceid))
if (mouse->type == M_TOUCH)
{
mx = 0;
my = 0;
if (CSQC_MousePosition(mouse->oldpos[0], mouse->oldpos[1], mouse->qdeviceid))
{
mx = 0;
my = 0;
}
}
else
{
if (mx || my)
if (CSQC_MouseMove(mx, my, mouse->qdeviceid))
{
mx = 0;
my = 0;
}
}
#endif
@ -433,7 +444,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
}
if (in_mlook.state[pnum] & 1)
V_StopPitchDrift (pnum);
V_StopPitchDrift (&cl.playerview[pnum]);
if (!strafe_y)
{

View File

@ -1887,7 +1887,7 @@ void INS_JoyMove (float *movements, int pnum)
{
cl.playerview[pnum].viewanglechange[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
}
V_StopPitchDrift(pnum);
V_StopPitchDrift(&cl.playerview[pnum]);
}
else
{
@ -1896,7 +1896,7 @@ void INS_JoyMove (float *movements, int pnum)
// *** this code can be removed when the lookspring bug is fixed
// *** the bug always has the lookspring feature on
if(lookspring.value == 0.0)
V_StopPitchDrift(pnum);
V_StopPitchDrift(&cl.playerview[pnum]);
}
}
else
@ -1957,7 +1957,7 @@ void INS_JoyMove (float *movements, int pnum)
{
cl.playerview[pnum].viewanglechange[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0;
}
V_StopPitchDrift(pnum);
V_StopPitchDrift(&cl.playerview[pnum]);
}
else
{
@ -1966,7 +1966,7 @@ void INS_JoyMove (float *movements, int pnum)
// *** this code can be removed when the lookspring bug is fixed
// *** the bug always has the lookspring feature on
if(lookspring.value == 0.0)
V_StopPitchDrift(pnum);
V_StopPitchDrift(&cl.playerview[pnum]);
}
}
break;

View File

@ -580,7 +580,7 @@ void Key_DefaultLinkClicked(char *text, char *info)
for (i = 0; i < cl.splitclients; i++)
{
if (cl.playernum[i] == player)
if (cl.playerview[i].playernum == player)
break;
}
if (i == cl.splitclients)
@ -594,7 +594,7 @@ void Key_DefaultLinkClicked(char *text, char *info)
else
{
//we're playing.
if (cls.protocol == CP_QUAKEWORLD && strcmp(cl.players[cl.playernum[0]].team, cl.players[player].team))
if (cls.protocol == CP_QUAKEWORLD && strcmp(cl.players[cl.playerview[0].playernum].team, cl.players[player].team))
Con_Footerf(true, " ^[[Join Team %s]\\cmd\\setinfo team %s^]", cl.players[player].team, cl.players[player].team);
}
Con_Footerf(true, " ^[%sgnore\\player\\%i\\action\\ignore^]", cl.players[player].ignored?"Uni":"I", player);
@ -655,6 +655,18 @@ void Key_DefaultLinkClicked(char *text, char *info)
Cbuf_AddText(va("\nconnect %s\n", c), RESTRICT_LOCAL);
return;
}
c = Info_ValueForKey(info, "join");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
Cbuf_AddText(va("\njoin %s\n", c), RESTRICT_LOCAL);
return;
}
c = Info_ValueForKey(info, "observe");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
Cbuf_AddText(va("\nobserve %s\n", c), RESTRICT_LOCAL);
return;
}
c = Info_ValueForKey(info, "qtv");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
@ -765,6 +777,9 @@ void Key_ConsoleRelease(int key, int unicode)
{
//okay, its a valid link that they clicked
*end = 0;
#ifdef PLUGINS
if (!Plug_ConsoleLink(buffer+2, info))
#endif
#ifdef CSQC_DAT
if (!CSQC_ConsoleLink(buffer+2, info))
#endif

View File

@ -796,445 +796,9 @@ void Menu_DownloadStuff_f (void)
}
}
}
#elif defined(WEBCLIENT)
#else
void Menu_DownloadStuff_f (void)
{
Con_Printf("Not yet reimplemented\n");
}
#endif
#if defined(WEBCLIENT)
static int numbootdownloads;
#include "fs.h"
#ifdef AVAIL_ZLIB
extern searchpathfuncs_t zipfilefuncs;
static int QDECL CL_BootDownload_Extract(const char *fname, int fsize, void *ptr, void *spath)
{
char buffer[512*1024];
int read;
void *zip = ptr;
flocation_t loc;
int slashes;
const char *s;
vfsfile_t *compressedpak;
vfsfile_t *decompressedpak;
if (zipfilefuncs.FindFile(zip, &loc, fname, NULL))
{
compressedpak = zipfilefuncs.OpenVFS(zip, &loc, "rb");
if (compressedpak)
{
//this extra logic is so we can handle things like nexuiz/data/blah.pk3
//as well as just data/blah.pk3
slashes = 0;
for (s = strchr(fname, '/'); s; s = strchr(s+1, '/'))
slashes++;
for (; slashes > 1; slashes--)
fname = strchr(fname, '/')+1;
if (!slashes)
{
FS_CreatePath(fname, FS_GAMEONLY);
decompressedpak = FS_OpenVFS(fname, "wb", FS_GAMEONLY);
}
else
{
FS_CreatePath(fname, FS_ROOT);
decompressedpak = FS_OpenVFS(fname, "wb", FS_ROOT);
}
if (decompressedpak)
{
for(;;)
{
read = VFS_READ(compressedpak, buffer, sizeof(buffer));
if (read <= 0)
break;
if (VFS_WRITE(decompressedpak, buffer, read) != read)
{
Con_Printf("write failed writing %s. disk full?\n", fname);
break;
}
}
VFS_CLOSE(decompressedpak);
}
VFS_CLOSE(compressedpak);
}
}
return true;
}
#endif
qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, qboolean copyprotect, qboolean istemporary, qboolean isexplicit);
void FS_GenCachedPakName(char *pname, char *crc, char *local, int llen);
static void CL_BootDownload_Complete(struct dl_download *dl)
{
char *q = strchr(dl->url, '?');
char *ext;
if (dl->file && dl->status == DL_FINISHED)
{
if (q) *q = '0';
ext = COM_FileExtension(dl->url);
if (q) *q = '?';
if (!stricmp(ext, "zip"))
{
#ifdef AVAIL_ZLIB
void *zip;
if (dl->status == DL_FINISHED)
zip = zipfilefuncs.OpenNew(dl->file, dl->url);
else
zip = NULL;
if (zip)
{
dl->file = NULL; //file is now owned by the zip context.
if (dl->user_ctx)
{
vfsfile_t *in, *out;
flocation_t loc;
qboolean found = false;
int crc;
found = zipfilefuncs.FindFile(zip, &loc, dl->user_ctx, NULL);
if (!found)
{
char *s = COM_SkipPath(dl->user_ctx);
if (s != dl->user_ctx)
found = zipfilefuncs.FindFile(zip, &loc, s, NULL);
}
if (found)
{
in = zipfilefuncs.OpenVFS(zip, &loc, "rb");
if (in)
{
char local[MAX_OSPATH];
FS_GenCachedPakName(dl->user_ctx, va("%i", dl->user_num), local, sizeof(local));
FS_CreatePath(local, FS_ROOT);
out = FS_OpenVFS(local, "wb", FS_ROOT);
if (out)
{
char buffer[8192];
int read;
for(;;)
{
read = VFS_READ(in, buffer, sizeof(buffer));
if (read <= 0)
break;
if (VFS_WRITE(out, buffer, read) != read)
{
Con_Printf("write failed writing %s. disk full?\n", local);
break;
}
}
VFS_CLOSE(out);
out = FS_OpenVFS(local, "rb", FS_ROOT);
crc = dl->user_num;
if (!FS_LoadPackageFromFile(out, dl->user_ctx, local, &crc, true, false, true))
{
if (crc == dl->user_num)
Con_Printf(CON_WARNING "Manifest package \"%s\" is unusable.\n", (char*)dl->user_ctx);
else
Con_Printf(CON_WARNING "Manifest package \"%s\" is unusable or has invalid crc. Stated crc %#x is not calculated crc %#x\n", (char*)dl->user_ctx, dl->user_num, crc);
FS_Remove(local, FS_ROOT);
}
}
}
VFS_CLOSE(in);
}
free(dl->user_ctx);
}
else
{
/*scan it to extract its contents*/
zipfilefuncs.EnumerateFiles(zip, "*/*.pk3", CL_BootDownload_Extract, zip);
zipfilefuncs.EnumerateFiles(zip, "*/*.pak", CL_BootDownload_Extract, zip);
zipfilefuncs.EnumerateFiles(zip, "*/*/*.pk3", CL_BootDownload_Extract, zip);
zipfilefuncs.EnumerateFiles(zip, "*/*/*.pak", CL_BootDownload_Extract, zip);
}
/*close it, delete the temp file from disk, etc*/
zipfilefuncs.ClosePath(zip);
/*restart the filesystem so those new files can be found*/
Cmd_ExecuteString("fs_restart\n", RESTRICT_LOCAL);
}
#endif
}
else
{
//okay, its named directly, write it out as it is
vfsfile_t *out;
int crc, *crcptr = &crc;
char local[MAX_OSPATH];
qboolean ispackage = (!stricmp(ext, "pak") || !stricmp(ext, "pk3"));
#ifndef NACL
if (ispackage)
{
FS_GenCachedPakName(dl->user_ctx, va("%i", dl->user_num), local, sizeof(local));
#else
//nacl permits any files to be listed in the manifest file, as there's no prior files to override/conflict, so don't mess about with crcs etc
crcptr = NULL;
Q_strncpyz(local, dl->user_ctx, sizeof(local));
if (1)
{
#endif
FS_CreatePath(local, FS_ROOT);
//write it out
out = FS_OpenVFS(local, "wb", FS_ROOT);
if (!out)
Con_Printf("Unable to open %s for writing\n", local);
else
{
char buffer[65535];
int read;
for(;;)
{
read = VFS_READ(dl->file, buffer, sizeof(buffer));
if (read <= 0)
break;
if (VFS_WRITE(out, buffer, read) != read)
{
Con_Printf("write failed writing %s. disk full?\n", local);
break;
}
}
VFS_CLOSE(out);
if (ispackage)
{
if (crcptr)
{
//load it as a package
out = FS_OpenVFS(local, "rb", FS_ROOT);
if (out)
{
crc = dl->user_num;
if (!FS_LoadPackageFromFile(out, dl->user_ctx, local, crcptr, true, false, true))
{
if (crc == dl->user_num)
Con_Printf(CON_WARNING "Manifest package \"%s\" is unusable.\n", (char*)dl->user_ctx);
else
Con_Printf(CON_WARNING "Manifest package \"%s\" is unusable or has invalid crc. Stated crc %#x is not calculated crc %#x\n", (char*)dl->user_ctx, dl->user_num, crc);
FS_Remove(local, FS_ROOT);
}
Cmd_ExecuteString("fs_restart\n", RESTRICT_LOCAL);
}
}
else
Cmd_ExecuteString("fs_restart\n", RESTRICT_LOCAL);
}
}
}
else
Con_Printf("File %s isn't a recognised package!\n", (char*)dl->user_ctx);
}
}
if (!--numbootdownloads)
{
CL_ExecInitialConfigs();
Cmd_StuffCmds();
Cbuf_Execute ();
Cmd_ExecuteString("vid_restart\n", RESTRICT_LOCAL);
CL_StartCinematicOrMenu();
}
free(dl->user_ctx);
}
static void CL_Manifest_Complete(struct dl_download *dl)
{
if (!dl->file || dl->status == DL_FAILED)
Con_Printf("Unable to load manifest from %s\n", dl->url);
else
{
vfsfile_t *f;
char buffer[1024];
char *fname;
int crc;
char local[MAX_OSPATH];
while(VFS_GETS(dl->file, buffer, sizeof(buffer)))
{
Cmd_TokenizeString(buffer, false, false);
if (!Cmd_Argc())
continue;
fname = Cmd_Argv(0);
if (*fname == '*')
{
//for future expansion.
/*if (!stricmp(fname, "*game"))
{
//switch current gamedir to the new one, so we don't end up downloading if they already have it installed.
//this should be quake/quake2/etc.
}*/
continue;
}
crc = strtoul(Cmd_Argv(1), NULL, 0);
f = FS_OpenVFS(fname, "rb", FS_ROOT);
if (f)
{
//should be loaded as needed
VFS_CLOSE(f);
}
else
{
FS_GenCachedPakName(fname, va("%i", crc), local, sizeof(local));
f = FS_OpenVFS(local, "rb", FS_ROOT);
if (f)
{
int truecrc = crc;
if (!FS_LoadPackageFromFile(f, fname, local, &truecrc, true, false, true))
{
if (crc == truecrc)
Con_Printf(CON_WARNING "Manifest package \"%s\" is unusable.\n", fname);
else
Con_Printf(CON_WARNING "Manifest package \"%s\" is unusable or has invalid crc. Stated crc %#x is not calculated crc %#x\n", fname, crc, truecrc);
FS_Remove(local, FS_ROOT);
}
}
else
{
int args = Cmd_Argc() - 2;
if (!args)
Con_Printf("No mirrors for \"%s\"\n", fname);
else
{
struct dl_download *ndl;
#ifdef NACL
args = 0; //nacl currently depends upon the browser's download cache for all file persistance, which means we want the same file every time.
//there's only one way to do that, sadly.
#else
args = rand() % args;
#endif
Con_Printf("Downloading \"%s\" from \"%s\"\n", fname, Cmd_Argv(2 + args));
ndl = HTTP_CL_Get(Cmd_Argv(2), "", CL_BootDownload_Complete);
if (ndl)
{
ndl->user_ctx = strdup(fname);
ndl->user_num = crc;
#ifdef MULTITHREAD
DL_CreateThread(ndl, FS_OpenTemp(), CL_BootDownload_Complete);
#endif
numbootdownloads++;
}
}
}
}
}
}
if (!--numbootdownloads)
{
CL_ExecInitialConfigs();
Cmd_StuffCmds();
Cbuf_Execute ();
Cmd_ExecuteString("vid_restart\n", RESTRICT_LOCAL);
CL_StartCinematicOrMenu();
}
}
qboolean CL_CheckBootDownloads(void)
{
char *downloads = fs_gamedownload.string;
char token[2048];
char *c, *s;
vfsfile_t *f;
struct dl_download *dl;
int mirrors;
int man = COM_CheckParm("-manifest");
if (man)
{
const char *fname = com_argv[man+1];
if (*fname)
{
Con_Printf("Checking manifest from \"%s\"\n", fname);
dl = HTTP_CL_Get(fname, "", CL_Manifest_Complete);
if (dl)
{
#ifdef MULTITHREAD
DL_CreateThread(dl, FS_OpenTemp(), CL_Manifest_Complete);
#endif
numbootdownloads++;
}
else
{
struct dl_download fake;
fake.file = VFSOS_Open(fname, "rb");
fake.status = fake.file?DL_FINISHED:DL_FAILED;
numbootdownloads++;
CL_Manifest_Complete(&fake);
if (fake.file)
VFS_CLOSE(fake.file);
}
}
}
while ((downloads = COM_ParseOut(downloads, token, sizeof(token))))
{
//FIXME: do we want to add some sort of file size indicator?
c = token;
while(*c && *c != ':' && *c != '|')
c++;
if (!*c) //erp?
continue;
*c++ = 0;
f = FS_OpenVFS(token, "rb", FS_ROOT);
if (f)
{
Con_DPrintf("Already have %s\n", token);
VFS_CLOSE(f);
continue;
}
mirrors = 1;
for (s = c; *s; s++)
{
if (*s == '|')
mirrors++;
}
mirrors = rand() % mirrors;
while(mirrors)
{
mirrors--;
while(*c != '|')
c++;
c++;
}
for (s = c; *s; s++)
{
if (*s == '|')
*s = 0;
}
Con_Printf("Attempting to download %s\n", c);
dl = HTTP_CL_Get(c, "", CL_BootDownload_Complete);
if (dl)
{
#ifdef MULTITHREAD
DL_CreateThread(dl, FS_OpenTemp(), CL_BootDownload_Complete);
#endif
numbootdownloads++;
}
}
return !numbootdownloads;
}
#else
qboolean CL_CheckBootDownloads(void)
{
if (COM_CheckParm("-manifest"))
Con_Printf("download manifests not supported in this build\n");
return true;
Con_Printf("Download menu not implemented in this build\n");
}
#endif

View File

@ -227,6 +227,23 @@ qboolean Media_FakeTrack(int i, qboolean loop)
if (i > 0 && i <= 999)
{
found = false;
if (!found && i <= 99)
{
sprintf(trackname, "music/track%02i.ogg", i);
found = COM_FCheckExists(trackname);
}
#ifdef WINAVI
if (!found && i <= 99)
{
sprintf(trackname, "music/track%02i.mp3", i);
found = COM_FCheckExists(trackname);
}
#endif
if (!found && i <= 99)
{
sprintf(trackname, "music/track%02i.wav", i);
found = COM_FCheckExists(trackname);
}
if (!found)
{
sprintf(trackname, "sound/cdtracks/track%03i.ogg", i);
@ -3145,6 +3162,9 @@ void Media_RecordDemo_f(void)
{
if (Cmd_Argc() < 2)
return;
if (Cmd_FromGamecode())
return;
CL_PlayDemo(Cmd_Argv(1));
if (Cmd_Argc() > 2)
Cmd_ShiftArgs(1, false);

View File

@ -369,7 +369,10 @@ typedef struct {
menucustom_t *list;
demoitem_t *selected;
demoitem_t *firstitem;
int pathlen;
char path[MAX_OSPATH];
int fsroot; //FS_ROOT, FS_GAME, FS_GAMEONLY. if FS_ROOT, executed command will have a leading #
char *command[64]; //these let the menu be used for nearly any sort of file browser.
char *ext[64];
@ -429,7 +432,7 @@ static void M_DemoDraw(int x, int y, menucustom_t *control, menu_t *menu)
item = item->next;
}
}
static void ShowDemoMenu (menu_t *menu, char *path);
static void ShowDemoMenu (menu_t *menu, const char *path);
static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key)
{
demomenu_t *info = menu->data;
@ -474,7 +477,7 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key)
if (info->selected)
{
if (info->selected->isdir)
ShowDemoMenu(menu, va("%s", info->selected->name));
ShowDemoMenu(menu, info->selected->name);
else
{
int extnum;
@ -485,7 +488,7 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key)
if (extnum == info->numext) //wasn't on our list of extensions.
extnum = 0;
Cbuf_AddText(va("%s \"%s\"\n", info->command[extnum], info->selected->name), RESTRICT_LOCAL);
Cbuf_AddText(va("%s \"%s%s\"\n", info->command[extnum], (info->fsroot==FS_ROOT)?"#":"", info->selected->name), RESTRICT_LOCAL);
M_ToggleMenu_f();
}
@ -640,15 +643,31 @@ static void M_Demo_Remove (menu_t *menu)
M_Demo_Flush(info);
}
static void ShowDemoMenu (menu_t *menu, char *path)
static void ShowDemoMenu (menu_t *menu, const char *path)
{
demomenu_t *info = menu->data;
int c;
char *s;
char match[256];
while (!strcmp(path+strlen(path)-3, "../"))
if (*path == '/')
path++;
Q_strncpyz(info->path, path, sizeof(info->path));
if (info->fsroot == FS_GAME)
{
if (!strcmp(path, "../"))
{
info->fsroot = FS_ROOT;
FS_NativePath("", FS_ROOT, info->path, sizeof(info->path));
while(s = strchr(info->path, '\\'))
*s = '/';
}
}
while (!strcmp(info->path+strlen(info->path)-3, "../"))
{
c = 0;
for (s = path+strlen(path)-3; s >= path; s--)
for (s = info->path+strlen(info->path)-3; s >= info->path; s--)
{
if (*s == '/')
{
@ -659,21 +678,42 @@ static void ShowDemoMenu (menu_t *menu, char *path)
}
}
if (c<2)
*path = '\0';
*info->path = '\0';
}
((demomenu_t*)menu->data)->selected = NULL;
((demomenu_t*)menu->data)->pathlen = strlen(path);
info->selected = NULL;
info->pathlen = strlen(info->path);
M_Demo_Flush(menu->data);
if (*path)
if (info->fsroot == FS_ROOT)
{
Q_snprintfz(match, sizeof(match), "%s../", path);
DemoAddItem(match, 0, menu->data, NULL);
s = strchr(info->path, '/');
if (s && strchr(s+1, '/'))
{
Q_snprintfz(match, sizeof(match), "%s../", info->path);
DemoAddItem(match, 0, info, NULL);
}
}
Q_snprintfz(match, sizeof(match), "%s*", path);
COM_EnumerateFiles(match, DemoAddItem, menu->data);
M_Demo_Flatten(menu->data);
else if (*info->path)
{
Q_snprintfz(match, sizeof(match), "%s../", info->path);
DemoAddItem(match, 0, info, NULL);
}
else if (info->fsroot == FS_GAME)
{
Q_snprintfz(match, sizeof(match), "../", info->path);
DemoAddItem(match, 0, info, NULL);
}
if (info->fsroot == FS_ROOT)
{
Q_snprintfz(match, sizeof(match), *info->path?"%s*":"/*", info->path);
Sys_EnumerateFiles("", match, DemoAddItem, info, NULL);
}
else
{
Q_snprintfz(match, sizeof(match), "%s*", info->path);
COM_EnumerateFiles(match, DemoAddItem, info);
}
M_Demo_Flatten(info);
}
void M_Menu_Demos_f (void)
@ -688,6 +728,8 @@ void M_Menu_Demos_f (void)
menu->remove = M_Demo_Remove;
info = menu->data;
info->fsroot = FS_GAME;
info->command[0] = "playdemo";
info->ext[0] = ".qwd";
info->command[1] = "playdemo";
@ -724,6 +766,8 @@ void M_Menu_MediaFiles_f (void)
menu->remove = M_Demo_Remove;
info = menu->data;
info->fsroot = FS_GAME;
info->ext[0] = ".m3u";
info->command[0] = "mediaplaylist";
info->ext[1] = ".mp3";

View File

@ -217,6 +217,17 @@ typedef struct vboarray_s
};
} vboarray_t;
//scissor rects
typedef struct
{
float x;
float y;
float width;
float height;
double dmin;
double dmax;
} srect_t;
typedef struct texnums_s {
texid_t base;
texid_t bump;
@ -340,6 +351,7 @@ typedef struct rendererinfo_s {
void (*BE_UploadAllLightmaps)(void);
void (*BE_SelectEntity)(struct entity_s *ent);
void (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour);
void (*BE_Scissor)(srect_t *rect);
/*check to see if an ent should be drawn for the selected light*/
qboolean (*BE_LightCullModel)(vec3_t org, struct model_s *model);
void (*BE_VBO_Begin)(vbobctx_t *ctx, unsigned int maxsize);
@ -378,3 +390,4 @@ typedef struct rendererinfo_s {
#define BE_VBO_Data rf->BE_VBO_Data
#define BE_VBO_Finish rf->BE_VBO_Finish
#define BE_VBO_Destroy rf->BE_VBO_Destroy
#define BE_Scissor rf->BE_Scissor

View File

@ -63,12 +63,12 @@ static qboolean csprogs_promiscuous;
static unsigned int csprogs_checksum;
static csqctreadstate_t *csqcthreads;
qboolean csqc_resortfrags;
qboolean csqc_drawsbar;
qboolean csqc_addcrosshair;
static int csqc_fakereadbyte;
world_t csqc_world;
static int csqc_lplayernum;
int csqc_playerseat; //can be negative.
static playerview_t *csqc_playerview;
static qboolean csqc_isdarkplaces;
static qboolean csqc_singlecheats; /*single player or cheats active, allowing custom addons*/
@ -130,6 +130,7 @@ extern sfx_t *cl_sfx_r_exp3;
globalentity(other, "other"); /*entity Written before entering most qc functions*/ \
\
globalfloat(maxclients, "maxclients"); /*float max number of players allowed*/ \
globalfloat(numclientseats, "numclientseats"); /*float number of seats/splitscreen clients running on this client*/ \
\
globalvector(forward, "v_forward"); /*vector written by anglevectors*/ \
globalvector(right, "v_right"); /*vector written by anglevectors*/ \
@ -191,46 +192,59 @@ typedef struct {
} csqcglobals_t;
static csqcglobals_t csqcg;
static void CSQC_ChangeLocalPlayer(int lplayernum)
playerview_t csqc_nullview;
//fixme: we should be using entity numbers, not view numbers.
static void CSQC_ChangeLocalPlayer(int seat)
{
csqc_lplayernum = lplayernum;
if (seat < 0 || seat >= MAX_SPLITS)
{
csqc_playerseat = -1;
csqc_playerview = &csqc_nullview;
}
else
{
csqc_playerseat = seat;
csqc_playerview = &cl.playerview[seat];
}
if (csqcg.player_localentnum)
{
if (cl.viewentity[lplayernum])
*csqcg.player_localentnum = cl.viewentity[lplayernum];
else if (cl.spectator && Cam_TrackNum(csqc_lplayernum) >= 0)
*csqcg.player_localentnum = Cam_TrackNum(csqc_lplayernum) + 1;
if (csqc_playerview->viewentity)
*csqcg.player_localentnum = csqc_playerview->viewentity;
else if (cl.spectator && Cam_TrackNum(csqc_playerview) >= 0)
*csqcg.player_localentnum = Cam_TrackNum(csqc_playerview) + 1;
else
*csqcg.player_localentnum = cl.playernum[lplayernum]+1;
*csqcg.player_localentnum = csqc_playerview->playernum+1;
}
if (csqcg.player_localnum)
*csqcg.player_localnum = cl.playernum[lplayernum];
*csqcg.player_localnum = csqc_playerview->playernum;
if (csqcg.view_angles)
{
csqcg.view_angles[0] = cl.playerview[csqc_lplayernum].viewangles[0];
csqcg.view_angles[1] = cl.playerview[csqc_lplayernum].viewangles[1];
csqcg.view_angles[2] = cl.playerview[csqc_lplayernum].viewangles[2];
csqcg.view_angles[0] = csqc_playerview->viewangles[0];
csqcg.view_angles[1] = csqc_playerview->viewangles[1];
csqcg.view_angles[2] = csqc_playerview->viewangles[2];
}
if (dpcompat_corruptglobals.ival || csqc_isdarkplaces)
{
if (csqcg.pmove_org)
{
csqcg.pmove_org[0] = cl.playerview[csqc_lplayernum].simorg[0];
csqcg.pmove_org[1] = cl.playerview[csqc_lplayernum].simorg[1];
csqcg.pmove_org[2] = cl.playerview[csqc_lplayernum].simorg[2];
csqcg.pmove_org[0] = csqc_playerview->simorg[0];
csqcg.pmove_org[1] = csqc_playerview->simorg[1];
csqcg.pmove_org[2] = csqc_playerview->simorg[2];
}
if (csqcg.input_angles)
{
csqcg.input_angles[0] = cl.playerview[csqc_lplayernum].viewangles[0];
csqcg.input_angles[1] = cl.playerview[csqc_lplayernum].viewangles[1];
csqcg.input_angles[2] = cl.playerview[csqc_lplayernum].viewangles[2];
csqcg.input_angles[0] = csqc_playerview->viewangles[0];
csqcg.input_angles[1] = csqc_playerview->viewangles[1];
csqcg.input_angles[2] = csqc_playerview->viewangles[2];
}
}
}
static void CSQC_FindGlobals(void)
{
extern cvar_t cl_forcesplitclient;
static float csphysicsmode = 0;
#define globalfloat(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
#define globalvector(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
@ -251,7 +265,7 @@ static void CSQC_FindGlobals(void)
if (csqcg.cltime)
*csqcg.cltime = cl.time;
CSQC_ChangeLocalPlayer(0);
CSQC_ChangeLocalPlayer(cl_forcesplitclient.ival?(cl_forcesplitclient.ival - 1) % cl.splitclients:0);
csqc_world.g.self = csqcg.self;
csqc_world.g.other = csqcg.other;
@ -548,7 +562,8 @@ static void QCBUILTIN PF_NoCSQC (pubprogfuncs_t *prinst, struct globalvars_s *pr
static void QCBUILTIN PF_cl_cprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *str = PF_VarString(prinst, 0, pr_globals);
SCR_CenterPrint(csqc_lplayernum, str, true);
if (csqc_playerseat >= 0)
SCR_CenterPrint(csqc_playerseat, str, true);
}
static void QCBUILTIN PF_cs_makevectors (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -590,13 +605,15 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
out->model = model;
rflags = in->xv->renderflags;
if (csqc_isdarkplaces)
rflags ^= CSQCRF_FRAMETIMESARESTARTTIMES;
if (rflags)
{
rflags = in->xv->renderflags;
if (rflags & CSQCRF_VIEWMODEL)
out->flags |= Q2RF_DEPTHHACK|Q2RF_WEAPONMODEL;
if (rflags & CSQCRF_EXTERNALMODEL)
out->externalmodelview = ~0;
out->flags |= Q2RF_EXTERNALMODEL;
if (rflags & CSQCRF_DEPTHHACK)
out->flags |= Q2RF_DEPTHHACK;
if (rflags & CSQCRF_ADDITIVE)
@ -604,7 +621,10 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
//CSQCRF_USEAXIS is below
if (rflags & CSQCRF_NOSHADOW)
out->flags |= RF_NOSHADOW;
//CSQCRF_FRAMETIMESARESTARTTIMES is below
//CSQCRF_FRAMETIMESARESTARTTIMES is handled by cs_getframestate below
if (rflags & CSQCRF_REMOVED)
Con_Printf("Warning: CSQCRF_NOAUTOADD is no longer supported\n");
}
effects = in->v->effects;
@ -898,6 +918,10 @@ static void QCBUILTIN PF_R_DynamicLight_Add(pubprogfuncs_t *prinst, struct globa
//if the org matches self, then attach it.
dl = CL_NewDlight (VectorCompare(self->v->origin, org)?-self->entnum:0, org, radius, -0.1, rgb[0], rgb[1], rgb[2]);
VectorCopy(csqcg.forward, dl->axis[0]);
VectorCopy(csqcg.right, dl->axis[1]);
VectorCopy(csqcg.up, dl->axis[2]);
if (pflags & PFLAGS_NOSHADOW)
dl->flags |= LFLAG_NOSHADOWS;
if (pflags & PFLAGS_CORONA)
@ -933,28 +957,59 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva
}
}
maxe = *prinst->parms->sv_num_edicts;
for (e=1; e < maxe; e++)
if (csqc_isdarkplaces)
{
ent = (void*)EDICT_NUM(prinst, e);
if (ent->isfree)
continue;
if ((int)ent->xv->drawmask & mask)
//hopelessly inefficient version for compat with DP.
maxe = *prinst->parms->sv_num_edicts;
for (e=1; e < maxe; e++)
{
ent = (void*)EDICT_NUM(prinst, e);
if (ent->isfree)
continue;
WPhys_RunThink (&csqc_world, (wedict_t*)ent);
if (ent->isfree)
continue;
if (ent->xv->predraw)
{
*csqcg.self = EDICT_TO_PROG(prinst, (void*)ent);
PR_ExecuteProgram(prinst, ent->xv->predraw);
if (ent->isfree || (int)ent->xv->renderflags & CSQCRF_NOAUTOADD)
if (ent->isfree)
continue; //bummer...
}
if (CopyCSQCEdictToEntity(ent, &rent))
if ((int)ent->xv->drawmask & mask)
{
CLQ1_AddShadow(&rent);
V_AddAxisEntity(&rent);
if (CopyCSQCEdictToEntity(ent, &rent))
{
CLQ1_AddShadow(&rent);
V_AddAxisEntity(&rent);
}
}
}
}
else
{
maxe = *prinst->parms->sv_num_edicts;
for (e=1; e < maxe; e++)
{
ent = (void*)EDICT_NUM(prinst, e);
if (ent->isfree)
continue;
if ((int)ent->xv->drawmask & mask)
{
if (ent->xv->predraw)
{
*csqcg.self = EDICT_TO_PROG(prinst, (void*)ent);
PR_ExecuteProgram(prinst, ent->xv->predraw);
if (ent->isfree || G_FLOAT(OFS_RETURN))
continue; //bummer...
}
if (CopyCSQCEdictToEntity(ent, &rent))
{
CLQ1_AddShadow(&rent);
V_AddAxisEntity(&rent);
}
}
}
}
@ -1173,29 +1228,24 @@ static void QCBUILTIN PF_cs_unproject (pubprogfuncs_t *prinst, struct globalvars
//clear scene, and set up the default stuff.
static void QCBUILTIN PF_R_ClearScene (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
extern cvar_t cl_forcesplitclient;
if (prinst->callargc > 0)
CSQC_ChangeLocalPlayer(G_FLOAT(OFS_PARM0));
csqc_rebuildmatricies = true;
CL_DecayLights ();
CL_TransitionEntities();
if (cl.worldmodel)
{
// do client side motion prediction
CL_PredictMove ();
}
#if defined(SKELETALOBJECTS) || defined(RAGDOLLS)
skel_dodelete(csqcprogs);
#endif
CL_ClearEntityLists();
V_CalcRefdef(csqc_lplayernum); //set up the defaults (for player 0)
V_ClearRefdef(csqc_playerview);
csqc_playerview->drawsbar = false; //csqc defaults to no sbar.
csqc_addcrosshair = false;
csqc_drawsbar = false;
V_CalcRefdef(csqc_playerview); //set up the defaults
}
static void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -1209,6 +1259,9 @@ static void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars
switch(parametertype)
{
case VF_LPLAYER:
*r = csqc_playerseat;
break;
case VF_FOV:
r[0] = r_refdef.fov_x;
r[1] = r_refdef.fov_y;
@ -1222,11 +1275,8 @@ static void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars
*r = r_refdef.fov_y;
break;
#ifdef warningmsg
#pragma warningmsg("fixme: AFOV not retrievable")
#endif
case VF_AFOV:
*r = r_refdef.fov_x;
*r = r_refdef.afov;
break;
case VF_ORIGIN:
@ -1257,12 +1307,12 @@ static void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars
break;
case VF_CL_VIEWANGLES_V:
VectorCopy(cl.playerview[csqc_lplayernum].viewangles, r);
VectorCopy(csqc_playerview->viewangles, r);
break;
case VF_CL_VIEWANGLES_X:
case VF_CL_VIEWANGLES_Y:
case VF_CL_VIEWANGLES_Z:
*r = cl.playerview[csqc_lplayernum].viewangles[parametertype-VF_CL_VIEWANGLES_X];
*r = csqc_playerview->viewangles[parametertype-VF_CL_VIEWANGLES_X];
break;
case VF_CARTESIAN_ANGLES:
@ -1301,7 +1351,7 @@ static void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars
*r = !(r_refdef.flags&Q2RDF_NOWORLDMODEL);
break;
case VF_ENGINESBAR:
*r = csqc_drawsbar;
*r = r_refdef.drawsbar;
break;
case VF_DRAWCROSSHAIR:
*r = csqc_addcrosshair;
@ -1343,38 +1393,49 @@ static void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars
G_FLOAT(OFS_RETURN) = 1;
switch(parametertype)
{
case VF_LPLAYER:
CSQC_ChangeLocalPlayer(*p);
V_CalcRefdef(csqc_playerview); //set up the default position+angles for the named player.
break;
case VF_VIEWENTITY:
//switches over EXTERNALMODEL flags and clears WEAPONMODEL flagged entities.
//FIXME: make affect addentities(MASK_ENGINE) calls too.
CL_EditExternalModels(*p);
break;
case VF_FOV:
//explicit fov overrides aproximate fov
r_refdef.afov = 0;
r_refdef.fov_x = p[0];
r_refdef.fov_y = p[1];
r_refdef.dirty |= RDFD_FOV;
break;
case VF_FOVX:
r_refdef.afov = 0;
r_refdef.fov_x = *p;
r_refdef.dirty |= RDFD_FOV;
break;
case VF_FOVY:
r_refdef.afov = 0;
r_refdef.fov_y = *p;
r_refdef.dirty |= RDFD_FOV;
break;
case VF_AFOV:
{
float frustumx, frustumy;
frustumy = tan(p[0] * (M_PI/360)) * 0.75;
if (prinst->callargc > 2)
frustumy *= G_FLOAT(OFS_PARM2);
frustumx = (frustumy * r_refdef.vrect.width) / r_refdef.vrect.height /* / vid.pixelheight*/;
r_refdef.fov_x = atan2(frustumx, 1) * (360/M_PI);
r_refdef.fov_y = atan2(frustumy, 1) * (360/M_PI);
}
r_refdef.afov = *p;
r_refdef.fov_x = 0;
r_refdef.fov_y = 0;
r_refdef.dirty |= RDFD_FOV;
break;
case VF_ORIGIN:
VectorCopy(p, r_refdef.vieworg);
cl.crouch[csqc_lplayernum] = 0;
csqc_playerview->crouch = 0;
break;
case VF_ORIGIN_Z:
cl.crouch[csqc_lplayernum] = 0;
csqc_playerview->crouch = 0;
case VF_ORIGIN_X:
case VF_ORIGIN_Y:
r_refdef.vieworg[parametertype-VF_ORIGIN_X] = *p;
@ -1390,12 +1451,12 @@ static void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars
break;
case VF_CL_VIEWANGLES_V:
VectorCopy(p, cl.playerview[csqc_lplayernum].viewangles);
VectorCopy(p, csqc_playerview->viewangles);
break;
case VF_CL_VIEWANGLES_X:
case VF_CL_VIEWANGLES_Y:
case VF_CL_VIEWANGLES_Z:
cl.playerview[csqc_lplayernum].viewangles[parametertype-VF_CL_VIEWANGLES_X] = *p;
csqc_playerview->viewangles[parametertype-VF_CL_VIEWANGLES_X] = *p;
break;
case VF_CARTESIAN_ANGLES:
@ -1403,40 +1464,44 @@ static void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars
break;
case VF_VIEWPORT:
r_refdef.vrect.x = p[0];
r_refdef.vrect.y = p[1];
r_refdef.grect.x = p[0];
r_refdef.grect.y = p[1];
p = G_VECTOR(OFS_PARM2);
r_refdef.vrect.width = p[0];
r_refdef.vrect.height = p[1];
r_refdef.grect.width = p[0];
r_refdef.grect.height = p[1];
r_refdef.dirty |= RDFD_FOV;
break;
case VF_SIZE_X:
r_refdef.vrect.width = *p;
r_refdef.grect.width = *p;
r_refdef.dirty |= RDFD_FOV;
break;
case VF_SIZE_Y:
r_refdef.vrect.height = *p;
r_refdef.grect.height = *p;
r_refdef.dirty |= RDFD_FOV;
break;
case VF_SIZE:
r_refdef.vrect.width = p[0];
r_refdef.vrect.height = p[1];
r_refdef.grect.width = p[0];
r_refdef.grect.height = p[1];
r_refdef.dirty |= RDFD_FOV;
break;
case VF_MIN_X:
r_refdef.vrect.x = *p;
r_refdef.grect.x = *p;
break;
case VF_MIN_Y:
r_refdef.vrect.y = *p;
r_refdef.grect.y = *p;
break;
case VF_MIN:
r_refdef.vrect.x = p[0];
r_refdef.vrect.y = p[1];
r_refdef.grect.x = p[0];
r_refdef.grect.y = p[1];
break;
case VF_DRAWWORLD:
r_refdef.flags = (r_refdef.flags&~Q2RDF_NOWORLDMODEL) | (*p?0:Q2RDF_NOWORLDMODEL);
break;
case VF_ENGINESBAR:
csqc_drawsbar = *p;
r_refdef.drawsbar = !!*p;
break;
case VF_DRAWCROSSHAIR:
csqc_addcrosshair = *p;
@ -1459,42 +1524,56 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars
if (cl.worldmodel)
R_PushDlights ();
r_refdef.currentplayernum = csqc_lplayernum;
r_refdef.playerview = csqc_playerview;
V_CalcGunPositionAngle(csqc_lplayernum, V_CalcBob(csqc_lplayernum, true));
V_CalcGunPositionAngle(csqc_playerview, V_CalcBob(csqc_playerview, true));
V_ApplyRefdef();
R_RenderView();
R2D_PolyBlend ();
vid.recalc_refdef = 1;
{
srect_t srect;
srect.x = (float)r_refdef.grect.x / vid.width;
srect.y = (float)r_refdef.grect.y / vid.height;
srect.width = (float)r_refdef.grect.width / vid.width;
srect.height = (float)r_refdef.grect.height / vid.height;
srect.dmin = -99999;
srect.dmax = 99999;
srect.y = (1-srect.y) - srect.height;
BE_Scissor(&srect);
}
if (csqc_drawsbar)
if (r_refdef.drawsbar)
{
#ifdef PLUGINS
Plug_SBar();
Plug_SBar (r_refdef.playerview);
#else
if (Sbar_ShouldDraw())
{
Sbar_Draw ();
Sbar_Draw (r_refdef.playerview);
Sbar_DrawScoreboard ();
}
#endif
SCR_TileClear ();
}
if (csqc_addcrosshair)
R2D_DrawCrosshair();
BE_Scissor(NULL);
}
static void QCBUILTIN PF_cs_getstati(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int stnum = G_FLOAT(OFS_PARM0);
G_INT(OFS_RETURN) = cl.playerview[csqc_lplayernum].stats[stnum];
G_INT(OFS_RETURN) = csqc_playerview->stats[stnum];
}
static void QCBUILTIN PF_cs_getstatbits(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ //convert an int stat into a qc float.
int stnum = G_FLOAT(OFS_PARM0);
int val = cl.playerview[csqc_lplayernum].stats[stnum];
int val = csqc_playerview->stats[stnum];
if (prinst->callargc > 1)
{
int first, count;
@ -1506,23 +1585,23 @@ static void QCBUILTIN PF_cs_getstatbits(pubprogfuncs_t *prinst, struct globalvar
G_FLOAT(OFS_RETURN) = (((unsigned int)val)&(((1<<count)-1)<<first))>>first;
}
else
G_FLOAT(OFS_RETURN) = cl.playerview[csqc_lplayernum].statsf[stnum];
G_FLOAT(OFS_RETURN) = csqc_playerview->statsf[stnum];
}
static void QCBUILTIN PF_cs_getstats(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int stnum = G_FLOAT(OFS_PARM0);
RETURN_TSTRING(cl.playerview[csqc_lplayernum].statsstr[stnum]);
RETURN_TSTRING(csqc_playerview->statsstr[stnum]);
/*
char out[17];
//the network protocol byteswaps
((unsigned int*)out)[0] = LittleLong(cl.playerview[csqc_lplayernum].stats[stnum+0]);
((unsigned int*)out)[1] = LittleLong(cl.playerview[csqc_lplayernum].stats[stnum+1]);
((unsigned int*)out)[2] = LittleLong(cl.playerview[csqc_lplayernum].stats[stnum+2]);
((unsigned int*)out)[3] = LittleLong(cl.playerview[csqc_lplayernum].stats[stnum+3]);
((unsigned int*)out)[0] = LittleLong(csqc_playerview->stats[stnum+0]);
((unsigned int*)out)[1] = LittleLong(csqc_playerview->stats[stnum+1]);
((unsigned int*)out)[2] = LittleLong(csqc_playerview->stats[stnum+2]);
((unsigned int*)out)[3] = LittleLong(csqc_playerview->stats[stnum+3]);
((unsigned int*)out)[4] = 0; //make sure it's null terminated
RETURN_TSTRING(out);*/
@ -2145,9 +2224,16 @@ static void cs_get_input_state (usercmd_t *cmd)
//get the input commands, and stuff them into some globals.
static void QCBUILTIN PF_cs_getinputstate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int f;
usercmd_t *cmd;
extern usercmd_t independantphysics[MAX_SPLITS];
int f = G_FLOAT(OFS_PARM0);
int seat = ((prinst->callargc>1)?G_FLOAT(OFS_PARM1):csqc_playerseat);
if (seat < 0 || seat >= MAX_SPLITS)
{
G_FLOAT(OFS_RETURN) = false;
return;
}
f = G_FLOAT(OFS_PARM0);
if (cl.paused && f >= cl.ackedmovesequence)
@ -2169,12 +2255,12 @@ static void QCBUILTIN PF_cs_getinputstate (pubprogfuncs_t *prinst, struct global
/*outgoing_sequence says how many packets have actually been sent, but there's an extra pending packet which has not been sent yet - be warned though, its data will change in the coming frames*/
if (f == cl.movesequence)
{
cmd = &independantphysics[csqc_lplayernum];
cmd = &independantphysics[seat];
for (f=0 ; f<3 ; f++)
cmd->angles[f] = ((int)(cl.playerview[csqc_lplayernum].viewangles[f]*65536.0/360)&65535);
cmd->angles[f] = ((int)(csqc_playerview->viewangles[f]*65536.0/360)&65535);
}
else
cmd = &cl.outframes[f&UPDATE_MASK].cmd[csqc_lplayernum];
cmd = &cl.outframes[f&UPDATE_MASK].cmd[seat];
cs_set_input_state(cmd);
@ -2331,7 +2417,7 @@ static void QCBUILTIN PF_cs_serverkey (pubprogfuncs_t *prinst, struct globalvars
else
ret = NET_AdrToString(adr, sizeof(adr), &cls.netchan.remote_address);
}
else if (!strcmp(keyname, "state"))
else if (!strcmp(keyname, "constate"))
{
if (cls.state == ca_disconnected)
ret = "disconnected";
@ -2422,7 +2508,7 @@ static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalv
{
if (csqc_resortfrags)
{
Sbar_SortFrags(false, false);
Sbar_SortFrags(true, false);
csqc_resortfrags = false;
}
if (pnum >= -scoreboardlines)
@ -2438,7 +2524,7 @@ static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalv
ret = buffer;
sprintf(ret, "%i", pnum+1);
}
else if (!*cl.players[pnum].userinfo)
else if (!*cl.players[pnum].name)
ret = ""; //player isn't on the server.
else if (!strcmp(keyname, "ping"))
{
@ -2469,6 +2555,30 @@ static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalv
ret = buffer;
sprintf(ret, "%i", (int)cl.players[pnum].entertime);
}
else if (!strcmp(keyname, "topcolor_rgb")) //packet loss
{
unsigned int col = cl.players[pnum].ttopcolor;
ret = buffer;
if (col < 16)
{
col = Sbar_ColorForMap(col);
sprintf(ret, "'%g %g %g'", host_basepal[col*3+0]/255.0, host_basepal[col*3+1]/255.0, host_basepal[col*3+2]/255.0);
}
else
sprintf(ret, "'%g %g %g'", ((col&0xff0000)>>16)/255.0, ((col&0x00ff00)>>8)/255.0, ((col&0x0000ff)>>0)/255.0);
}
else if (!strcmp(keyname, "bottomcolor_rgb")) //packet loss
{
unsigned int col = cl.players[pnum].tbottomcolor;
ret = buffer;
if (col < 16)
{
col = Sbar_ColorForMap(col);
sprintf(ret, "'%g %g %g'", host_basepal[col*3+0]/255.0, host_basepal[col*3+1]/255.0, host_basepal[col*3+2]/255.0);
}
else
sprintf(ret, "'%g %g %g'", ((col&0xff0000)>>16)/255.0, ((col&0x00ff00)>>8)/255.0, ((col&0x0000ff)>>0)/255.0);
}
else if (!strcmp(keyname, "ignored")) //checks to see if a player has locally been set to ignored (for text chat)
{
ret = buffer;
@ -2488,7 +2598,7 @@ static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalv
else if (!strcmp(keyname, "voiploudness"))
{
ret = buffer;
if (pnum == cl.playernum[0])
if (pnum == csqc_playerview->playernum)
sprintf(ret, "%i", S_Voip_Loudness(false));
else
*ret = 0;
@ -3573,7 +3683,7 @@ void CSQC_PlayerStateToCSQC(int pnum, player_state_t *srcp, csqcedict_t *ent)
{
ent->xv->entnum = pnum+1;
if (cl.spectator && !Cam_DrawPlayer(0, pnum))
if (cl.spectator && !Cam_DrawEntity(0, pnum+1))
{
ent->v->modelindex = 0;
}
@ -4243,8 +4353,9 @@ static struct {
{"strpad", PF_strpad, 225}, // #225 string strpad(float pad, string str1, ...) strpad (FTE_STRINGS)
{"infoadd", PF_infoadd, 226}, // #226 string(string old, string key, string value) infoadd
{"infoget", PF_infoget, 227}, // #227 string(string info, string key) infoget
{"strcmp", PF_strncmp, 228}, // #228 float(string s1, string s2) strcmp (FTE_STRINGS)
{"strncmp", PF_strncmp, 228}, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
{"strcasecmp", PF_strcasecmp, 229}, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
{"strcasecmp", PF_strncasecmp, 229}, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
//230
{"strncasecmp", PF_strncasecmp, 230}, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
@ -4358,7 +4469,7 @@ static struct {
//330
{"getstati", PF_cs_getstati, 330}, // #330 float(float stnum) getstati (EXT_CSQC)
{"getstatbits", PF_cs_getstatbits, 331}, // #331 float(float stnum) getstatbits (EXT_CSQC)
{"getstatf", PF_cs_getstatbits, 331}, // #331 float(float stnum) getstatf (EXT_CSQC)
{"getstats", PF_cs_getstats, 332}, // #332 string(float firststnum) getstats (EXT_CSQC)
{"setmodelindex", PF_cs_SetModelIndex, 333}, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
{"modelnameforindex", PF_cs_ModelnameForIndex, 334}, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
@ -4562,20 +4673,20 @@ static struct {
#ifndef NOMEDIA
//DP_GECKO_SUPPORT
{"gecko_create", PF_cs_gecko_create, 487}, // #487 float(string name) gecko_create( string name )
{"gecko_destroy", PF_cs_gecko_destroy, 488}, // #488 void(string name) gecko_destroy( string name )
{"gecko_navigate", PF_cs_gecko_navigate, 489}, // #489 void(string name) gecko_navigate( string name, string URI )
{"gecko_keyevent", PF_cs_gecko_keyevent, 490}, // #490 float(string name) gecko_keyevent( string name, float key, float eventtype )
{"gecko_mousemove", PF_cs_gecko_mousemove, 491}, // #491 void gecko_mousemove( string name, float x, float y )
{"gecko_resize", PF_cs_gecko_resize, 492}, // #492 void gecko_resize( string name, float w, float h )
{"gecko_create", PF_cs_gecko_create, 487}, // #487 float(string name) gecko_create( string name )
{"gecko_destroy", PF_cs_gecko_destroy, 488}, // #488 void(string name) gecko_destroy( string name )
{"gecko_navigate", PF_cs_gecko_navigate, 489}, // #489 void(string name) gecko_navigate( string name, string URI )
{"gecko_keyevent", PF_cs_gecko_keyevent, 490}, // #490 float(string name) gecko_keyevent( string name, float key, float eventtype )
{"gecko_mousemove", PF_cs_gecko_mousemove, 491}, // #491 void gecko_mousemove( string name, float x, float y )
{"gecko_resize", PF_cs_gecko_resize, 492}, // #492 void gecko_resize( string name, float w, float h )
{"gecko_get_texture_extent",PF_cs_gecko_get_texture_extent, 493}, // #493 vector gecko_get_texture_extent( string name )
#endif
//DP_QC_CRC16
{"crc16", PF_crc16, 494}, // #494 float(float caseinsensitive, string s, ...) crc16
{"crc16", PF_crc16, 494}, // #494 float(float caseinsensitive, string s, ...) crc16
//DP_QC_CVAR_TYPE
{"cvar_type", PF_cvar_type, 495}, // #495 float(string name) cvar_type
{"cvar_type", PF_cvar_type, 495}, // #495 float(string name) cvar_type
//DP_QC_ENTITYDATA
{"numentityfields", PF_numentityfields, 496}, // #496 float() numentityfields
@ -4613,21 +4724,23 @@ static struct {
{"gettime", PF_cs_gettime, 519},
{"keynumtostring", PF_cl_keynumtostring, 520},
{"keynumtostring_omgwtf", PF_cl_keynumtostring, 520},
{"findkeysforcommand", PF_cl_findkeysforcommand, 521},
{"loadfromdata", PF_loadfromdata, 529},
{"loadfromfile", PF_loadfromfile, 530},
{"soundlength", PF_soundlength, 534},
{"buf_loadfile", PF_buf_loadfile, 535},
{"buf_writefile", PF_buf_writefile, 536},
{"callfunction", PF_callfunction, 605},
{"writetofile", PF_writetofile, 606},
{"isfunction", PF_isfunction, 607},
{"parseentitydata", PF_parseentitydata, 608},
{"keynumtostring", PF_cl_keynumtostring, 609},
{"keynumtostring_menu", PF_cl_keynumtostring, 609}, //while present in dp's menuqc, dp doesn't actually support keynumtostring=609 in csqc. Which is probably a good thing because csqc would have 3 separate versions if it did.
{"findkeysforcommand", PF_cl_findkeysforcommand, 610},
{"findkeysforcommand_dp", PF_cl_findkeysforcommand, 610},
{"gethostcachevalue", PF_cl_gethostcachevalue, 611},
{"gethostcachestring", PF_cl_gethostcachestring, 612},
{"parseentitydata", PF_parseentitydata, 613},
@ -4987,24 +5100,26 @@ qboolean CSQC_Inited(void)
qboolean CSQC_UnconnectedOkay(qboolean inprinciple)
{
#ifndef _DEBUG
return false;
#endif
if (!pr_csqc_formenus.ival)
return false;
if (!inprinciple)
{
if (!csqcprogs)
return false;
return true;
}
else
{
if (pr_csqc_formenus.ival)
return true;
return false;
}
return true;
}
qboolean CSQC_UnconnectedInit(void)
{
return false;
if (!CSQC_UnconnectedOkay(false))
return false;
return CSQC_Init(true, true, 0);
}
double csqctime;
@ -5232,6 +5347,7 @@ void CSQC_RendererRestarted(void)
void CSQC_WorldLoaded(void)
{
char *map;
csqcedict_t *worldent;
if (!csqcprogs)
@ -5239,7 +5355,10 @@ void CSQC_WorldLoaded(void)
if (csqcmapentitydataloaded)
return;
csqcmapentitydataloaded = true;
csqcmapentitydata = cl.worldmodel->entities;
map = Info_ValueForKey(cl.serverinfo, "map");
csqcmapentitydata = map?COM_LoadFile(va("maps/%s.ent", map), 1):NULL;
if (!csqcmapentitydata)
csqcmapentitydata = cl.worldmodel->entities;
csqc_world.worldmodel = cl.worldmodel;
#ifdef USEODE
@ -5250,6 +5369,8 @@ void CSQC_WorldLoaded(void)
worldent->v->solid = SOLID_BSP;
csqc_setmodel(csqcprogs, worldent, 1);
worldent->readonly = false; //just in case
if (csqcg.worldloaded)
PR_ExecuteProgram(csqcprogs, csqcg.worldloaded);
csqcmapentitydata = NULL;
@ -5470,6 +5591,7 @@ qboolean CSQC_DrawView(void)
int ticlimit = 10;
float mintic = 0.01;
double clframetime = host_frametime;
extern cvar_t cl_forcesplitclient;
csqc_resortfrags = true;
@ -5484,33 +5606,42 @@ qboolean CSQC_DrawView(void)
if (csqcg.frametime)
*csqcg.frametime = host_frametime;
while(1)
if (!csqc_isdarkplaces)
{
host_frametime = cl.servertime - csqc_world.physicstime;
if (host_frametime < mintic)
break;
if (!--ticlimit)
while(1)
{
csqc_world.physicstime = cl.servertime;
break;
host_frametime = cl.servertime - csqc_world.physicstime;
if (host_frametime < mintic)
break;
if (!--ticlimit)
{
csqc_world.physicstime = cl.servertime;
break;
}
if (host_frametime > mintic)
host_frametime = mintic;
csqc_world.physicstime += host_frametime;
#ifdef USEODE
World_ODE_Frame(&csqc_world, host_frametime, 800);
#endif
World_Physics_Frame(&csqc_world);
}
if (host_frametime > mintic)
host_frametime = mintic;
csqc_world.physicstime += host_frametime;
#ifdef USEODE
World_ODE_Frame(&csqc_world, host_frametime, 800);
#endif
World_Physics_Frame(&csqc_world);
}
host_frametime = clframetime;
//always revert to a usable default.
CSQC_ChangeLocalPlayer(cl_forcesplitclient.ival?(cl_forcesplitclient.ival - 1) % cl.splitclients:0);
if (csqcg.frametime)
*csqcg.frametime = host_frametime;
DropPunchAngle (0);
if (csqcg.numclientseats)
*csqcg.numclientseats = cl.splitclients;
DropPunchAngle (csqc_playerview);
if (cl.worldmodel)
R_LessenStains();
@ -5535,7 +5666,9 @@ qboolean CSQC_DrawView(void)
if (csqcg.intermission)
*csqcg.intermission = cl.intermission;
CSQC_ChangeLocalPlayer(0);
CL_TransitionEntities();
if (cl.worldmodel)
CL_PredictMove ();
if (csqcg.cltime)
*csqcg.cltime = cl.time;
@ -5588,8 +5721,8 @@ qboolean CSQC_MousePosition(float xabs, float yabs, int devid)
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
G_FLOAT(OFS_PARM0) = CSIE_MOUSEABS;
G_FLOAT(OFS_PARM1) = xabs;
G_FLOAT(OFS_PARM2) = yabs;
G_FLOAT(OFS_PARM1) = (xabs * vid.width) / vid.pixelwidth;
G_FLOAT(OFS_PARM2) = (yabs * vid.height) / vid.pixelheight;
G_FLOAT(OFS_PARM3) = devid;
PR_ExecuteProgram (csqcprogs, csqcg.input_event);

View File

@ -10,7 +10,7 @@
#if defined(MENU_DAT) || defined(CSQC_DAT)
#include "cl_master.h"
extern int r2d_be_flags;
extern unsigned int r2d_be_flags;
#define DRAWFLAG_NORMAL 0
#define DRAWFLAG_ADD 1
#define DRAWFLAG_MODULATE 2
@ -36,54 +36,35 @@ void QCBUILTIN PF_CL_drawfill (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
float *size = G_VECTOR(OFS_PARM1);
float *rgb = G_VECTOR(OFS_PARM2);
float alpha = G_FLOAT(OFS_PARM3);
int flag = prinst->callargc >= 5?G_FLOAT(OFS_PARM4):0;
r2d_be_flags = PF_SelectDPDrawFlag(flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_FillBlock(pos[0], pos[1], size[0], size[1]);
r2d_be_flags = 0;
G_FLOAT(OFS_RETURN) = 1;
}
//void drawsetcliparea(float x, float y, float width, float height) = #458;
void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float x = G_FLOAT(OFS_PARM0), y = G_FLOAT(OFS_PARM1), w = G_FLOAT(OFS_PARM2), h = G_FLOAT(OFS_PARM3);
srect_t srect;
srect.x = G_FLOAT(OFS_PARM0) / (float)vid.width;
srect.y = (G_FLOAT(OFS_PARM1) / (float)vid.height);
srect.width = G_FLOAT(OFS_PARM2) / (float)vid.width;
srect.height = G_FLOAT(OFS_PARM3) / (float)vid.height;
srect.dmin = -99999;
srect.dmax = 99999;
srect.y = (1-srect.y) - srect.height;
BE_Scissor(&srect);
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL && qglScissor)
{
x *= (float)vid.pixelwidth/vid.width;
y *= (float)vid.pixelheight/vid.height;
w *= (float)vid.pixelwidth/vid.width;
h *= (float)vid.pixelheight/vid.height;
//add a pixel because this makes DP's menus come out right.
x-=1;
y-=1;
w+=2;
h+=2;
qglScissor (x, vid.pixelheight-(y+h), w, h);
qglEnable(GL_SCISSOR_TEST);
G_FLOAT(OFS_RETURN) = 1;
return;
}
#endif
G_FLOAT(OFS_RETURN) = 0;
G_FLOAT(OFS_RETURN) = 1;
}
//void drawresetcliparea(void) = #459;
void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL)
{
qglDisable(GL_SCISSOR_TEST);
G_FLOAT(OFS_RETURN) = 1;
return;
}
#endif
G_FLOAT(OFS_RETURN) = 0;
BE_Scissor(NULL);
G_FLOAT(OFS_RETURN) = 1;
}
#define FONT_SLOTS 16
@ -265,7 +246,7 @@ void QCBUILTIN PF_CL_drawcolouredstring (pubprogfuncs_t *prinst, struct globalva
g = G_FLOAT(OFS_PARM3 + 1);
b = G_FLOAT(OFS_PARM3 + 2);
alpha = G_FLOAT(OFS_PARM4);
flag = G_FLOAT(OFS_PARM5);
flag = G_FLOAT(OFS_PARM5); //flag is mandatory to distinguish it.
}
else
{
@ -273,7 +254,7 @@ void QCBUILTIN PF_CL_drawcolouredstring (pubprogfuncs_t *prinst, struct globalva
g = 1;
b = 1;
alpha = G_FLOAT(OFS_PARM3);
flag = G_FLOAT(OFS_PARM4);
flag = prinst->callargc >= 5?G_FLOAT(OFS_PARM4):0;
}
if (!text)
@ -315,7 +296,7 @@ void QCBUILTIN PF_CL_stringwidth(pubprogfuncs_t *prinst, struct globalvars_s *pr
end = COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), !usecolours);
PR_CL_BeginString(prinst, 0, 0, size?size[0]:8, size?size[1]:8, &px, &py);
px = Font_LineWidth(buffer, end);
px = Font_LineScaleWidth(buffer, end);
Font_EndString(NULL);
G_FLOAT(OFS_RETURN) = (px * vid.width) / vid.rotpixelwidth;
@ -329,7 +310,7 @@ void QCBUILTIN PF_CL_drawpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
float *size = G_VECTOR(OFS_PARM2);
float *rgb = G_VECTOR(OFS_PARM3);
float alpha = G_FLOAT(OFS_PARM4);
int flag = (int)G_FLOAT(OFS_PARM5);
int flag = prinst->callargc >= 6?(int)G_FLOAT(OFS_PARM5):0;
mpic_t *p;
@ -354,7 +335,7 @@ void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr
float *srcSize = G_VECTOR(OFS_PARM4);
float *rgb = G_VECTOR(OFS_PARM5);
float alpha = G_FLOAT(OFS_PARM6);
int flag = (int) G_FLOAT(OFS_PARM7);
int flag = prinst->callargc >= 8?(int) G_FLOAT(OFS_PARM7):0;
mpic_t *p;
@ -434,7 +415,7 @@ void QCBUILTIN PF_CL_drawcharacter (pubprogfuncs_t *prinst, struct globalvars_s
float *size = G_VECTOR(OFS_PARM2);
float *rgb = G_VECTOR(OFS_PARM3);
float alpha = G_FLOAT(OFS_PARM4);
int flag = G_FLOAT(OFS_PARM5);
int flag = prinst->callargc >= 6?G_FLOAT(OFS_PARM5):0;
float x, y;
@ -468,7 +449,7 @@ void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s
float *size = G_VECTOR(OFS_PARM2);
float *rgb = G_VECTOR(OFS_PARM3);
float alpha = G_FLOAT(OFS_PARM4);
// float flag = G_FLOAT(OFS_PARM5);
int flag = prinst->callargc >= 6?G_FLOAT(OFS_PARM5):0;
float x, y;
unsigned int c;
int error;
@ -479,6 +460,7 @@ void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s
return;
}
r2d_be_flags = PF_SelectDPDrawFlag(flag);
PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &x, &y);
Font_ForceColour(rgb[0], rgb[1], rgb[2], alpha);
@ -500,31 +482,57 @@ void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s
}
Font_InvalidateColour();
Font_EndString(NULL);
r2d_be_flags = 0;
}
//void (float width, vector rgb, float alpha, float flags, vector pos1, ...) drawline;
//void (float width, vector pos1, vector pos2, vector rgb, float alpha, optional float flags) drawline;
void QCBUILTIN PF_CL_drawline (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float *rgb = G_VECTOR(OFS_PARM1);
float alpha = G_FLOAT(OFS_PARM2);
float *pos = G_VECTOR(OFS_PARM4);
int numpoints = prinst->callargc-4;
//float width = G_FLOAT(OFS_PARM0);
float *point1 = G_VECTOR(OFS_PARM1);
float *point2 = G_VECTOR(OFS_PARM2);
float *rgb = G_VECTOR(OFS_PARM3);
float alpha = G_FLOAT(OFS_PARM4);
int flags = prinst->callargc >= 6?G_FLOAT(OFS_PARM5):0;
shader_t *shader_draw_line;
#ifdef GLQUAKE // :(
mesh_t mesh;
vecV_t vpos[2];
vec2_t vst[2];
vec4_t vcol[2];
index_t idx[2];
if (qrenderer == QR_OPENGL)
{
qglColor4f(rgb[0], rgb[1], rgb[2], alpha);
qglBegin(GL_LINES);
while (numpoints-->0)
{
qglVertex3fv(pos);
pos += 3;
}
memset(&mesh, 0, sizeof(mesh));
mesh.indexes = idx;
mesh.colors4f_array = vpos;
mesh.st_array = vst;
mesh.colors4f_array = vcol;
qglEnd();
}
#endif
VectorCopy(point1, vpos[0]);
Vector2Set(vst[0], 0, 0);
Vector4Set(vcol[0], rgb[0], rgb[1], rgb[2], alpha);
VectorCopy(point2, vpos[1]);
Vector2Set(vst[1], 0, 0);
Vector4Set(vcol[1], rgb[0], rgb[1], rgb[2], alpha);
mesh.numvertexes = 2;
mesh.indexes[0] = 0;
mesh.indexes[1] = 1;
mesh.numindexes = 2;
//this shader lookup might get pricy.
shader_draw_line = R_RegisterShader("shader_draw_line",
"{\n"
"program defaultfill\n"
"{\n"
"map $whiteimage\n"
"rgbgen exactvertex\n"
"alphagen vertex\n"
"}\n"
"}\n");
BE_DrawMesh_Single(shader_draw_line, &mesh, NULL, &shader_draw_line->defaulttextures, flags|BEF_LINES);
}
//vector drawgetimagesize(string pic) = #460;
@ -1309,8 +1317,9 @@ static struct {
{"strpad", PF_strpad, 225},
{"infoadd", PF_infoadd, 226},
{"infoget", PF_infoget, 227},
{"strcmp", PF_strncmp, 228},
{"strncmp", PF_strncmp, 228},
{"strcasecmp", PF_strcasecmp, 229},
{"strcasecmp", PF_strncasecmp, 229},
{"strncasecmp", PF_strncasecmp, 230},
//gap
{"shaderforname", PF_shaderforname, 238},
@ -1323,7 +1332,7 @@ static struct {
{"hash_getkey", PF_hash_getkey, 292},
//gap
{"print", PF_print, 339},
{"keynumtostring", PF_cl_keynumtostring, 340},
{"keynumtostring_csqc", PF_cl_keynumtostring, 340},
{"stringtokeynum", PF_cl_stringtokeynum, 341},
{"getkeybind", PF_cl_getkeybind, 342},
//gap
@ -1415,6 +1424,8 @@ static struct {
{"cvar_description", PF_cvar_description, 518},
//gap
{"soundlength", PF_soundlength, 534},
{"buf_loadfile", PF_buf_loadfile, 535},
{"buf_writefile", PF_buf_writefile, 536},
//gap
{"setkeydest", PF_cl_setkeydest, 601},
{"getkeydest", PF_cl_getkeydest, 602},

View File

@ -248,7 +248,7 @@ extern qboolean noclip_anglehack;
extern quakeparms_t host_parms;
extern cvar_t fs_gamename;
extern cvar_t fs_gamedownload;
extern cvar_t fs_gamemanifest;
extern cvar_t com_protocolname;
extern cvar_t com_modname;
extern cvar_t com_nogamedirnativecode;
@ -276,6 +276,7 @@ NORETURN void VARGS Host_Error (char *error, ...) LIKEPRINTF(1);
NORETURN void VARGS Host_EndGame (char *message, ...) LIKEPRINTF(1);
qboolean Host_SimulationTime(float time);
double Host_Frame (double time);
qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file);
void Host_Quit_f (void);
void VARGS Host_ClientCommands (char *fmt, ...) LIKEPRINTF(1);
void Host_ShutdownServer (qboolean crash);

View File

@ -174,9 +174,9 @@ void R2D_Init(void)
"}\n"
"}\n");
if (!TEXVALID(draw_backtile->defaulttextures.base))
draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/backtile", NULL, IF_2D|IF_NOPICMIP|IF_NOMIPMAP);
draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP);
if (!TEXVALID(draw_backtile->defaulttextures.base))
draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/menu/backtile", NULL, IF_2D|IF_NOPICMIP|IF_NOMIPMAP);
draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/menu/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP);
shader_draw_fill = R_RegisterShader("fill_opaque",
"{\n"
@ -468,7 +468,7 @@ void R2D_TransPicTranslate (int x, int y, int width, int height, qbyte *pic, qby
translate_shader->defaulttextures.base = translate_texture;
}
/* could avoid reuploading already translated textures but this func really isn't used enough anyway */
R_Upload(translate_texture, NULL, TF_RGBA32, trans, NULL, 64, 64, IF_2D|IF_NOMIPMAP|IF_NOGAMMA);
R_Upload(translate_texture, NULL, TF_RGBA32, trans, NULL, 64, 64, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
R2D_ScalePic(x, y, width, height, translate_shader);
}
@ -722,8 +722,6 @@ void R2D_Console_Resize(void)
vid.width = cwidth;
vid.height = cheight;
vid.recalc_refdef = true;
if (font_tiny)
Font_Free(font_tiny);
font_tiny = NULL;
@ -1055,7 +1053,7 @@ void R2D_Crosshair_Update(void)
return;
else if (crosshairimage.string[0] && c == 1)
{
shader_crosshair->defaulttextures.base = R_LoadHiResTexture (crosshairimage.string, "crosshairs", IF_2D|IF_NOMIPMAP|IF_NOGAMMA);
shader_crosshair->defaulttextures.base = R_LoadHiResTexture (crosshairimage.string, "crosshairs", IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
if (TEXVALID(shader_crosshair->defaulttextures.base))
return;
}
@ -1066,7 +1064,7 @@ void R2D_Crosshair_Update(void)
c = c % (sizeof(crosshair_pixels) / (CS_HEIGHT*sizeof(*crosshair_pixels)));
if (!TEXVALID(ch_int_texture))
ch_int_texture = R_AllocNewTexture("***crosshair***", CS_WIDTH, CS_HEIGHT, IF_2D|IF_NOMIPMAP);
ch_int_texture = R_AllocNewTexture("***crosshair***", CS_WIDTH, CS_HEIGHT, IF_UIPIC|IF_NOMIPMAP);
shader_crosshair->defaulttextures.base = ch_int_texture;
Q_memset(crossdata, 0, sizeof(crossdata));
@ -1083,7 +1081,7 @@ void R2D_Crosshair_Update(void)
}
}
R_Upload(ch_int_texture, NULL, TF_RGBA32, crossdata, NULL, CS_WIDTH, CS_HEIGHT, IF_2D|IF_NOMIPMAP|IF_NOGAMMA);
R_Upload(ch_int_texture, NULL, TF_RGBA32, crossdata, NULL, CS_WIDTH, CS_HEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
}
@ -1128,7 +1126,7 @@ void R2D_DrawCrosshair(void)
size = -size;
for (sc = 0; sc < cl.splitclients; sc++)
{
SCR_CrosshairPosition(sc, &x, &y);
SCR_CrosshairPosition(&cl.playerview[sc], &x, &y);
Font_BeginScaledString(font_conchar, x, y, size, size, &sx, &sy);
sx -= Font_CharScaleWidth('+' | 0xe000 | CON_WHITEMASK)/2;
sy -= Font_CharScaleHeight()/2;
@ -1163,7 +1161,7 @@ void R2D_DrawCrosshair(void)
R2D_ImageColours(ch_color[0], ch_color[1], ch_color[2], crosshairalpha.value);
for (sc = 0; sc < cl.splitclients; sc++)
{
SCR_CrosshairPosition(sc, &x, &y);
SCR_CrosshairPosition(&cl.playerview[sc], &x, &y);
//translate to pixel coord, for rounding
x = ((x-sizex+(sizex/CS_WIDTH))*vid.rotpixelwidth) / (float)vid.width;

View File

@ -1295,6 +1295,26 @@ char *particle_set_highfps =
char *particle_set_high =
///////////////////////////////
//rain
"r_part te_rain\n"
"{\n"
"texture ball; scalefactor 1; count 1; alpha 0.4; rgb 255 255 255; die 2; veladd 2; scale 2; type texturedspark\n"
"cliptype rainsplash\n"
"clipbounce 1\n"
"clipcount 5\n"
"}\n"
"r_part rainsplash\n"
"{\n"
"randomvel 50 50\n"
"count 1;\n"
"texture ball; scalefactor 1; alpha 0.1; rgb 255 255 255; die 0.4; scale 50;\n"
"stretchfactor 4\n"
"veladd 50; scale 1; type texturedspark\n"
"gravity 400\n"
"}\n"
///////////////////////////////
//rocket trail

View File

@ -2579,7 +2579,11 @@ void Surf_BuildModelLightmaps (model_t *m)
{
for (t = m->numtextures-1; t >= 0; t--)
{
ptype = P_FindParticleType(va("tex_%s", m->textures[t]->name));
char *pn = va("tex_%s", m->textures[t]->name);
char *h = strchr(pn, '#');
if (h)
*h = 0;
ptype = P_FindParticleType(pn);
if (ptype != P_INVALID)
{

View File

@ -119,7 +119,6 @@ typedef struct entity_s
framestate_t framestate;
unsigned int externalmodelview;
int flags;
refEntityType_t rtype;
@ -139,21 +138,25 @@ typedef struct entity_s
#endif
} entity_t;
#define RDFD_FOV 1
typedef struct
{
vrect_t vrect; // subwindow in video for refresh
// FIXME: not need vrect next field here?
vrect_t grect; // game rectangle. fullscreen except for csqc/splitscreen.
vrect_t vrect; // subwindow in grect for 3d view
vec3_t pvsorigin; /*render the view using this point for pvs (useful for mirror views)*/
vec3_t vieworg; /*logical view center*/
vec3_t viewangles;
vec3_t viewaxis[3]; /*forward, left, up (NOT RIGHT)*/
float fov_x, fov_y;
float fov_x, fov_y, afov;
int flags;
qboolean drawsbar;
int flags; //(Q2)RDF_ flags
int dirty;
int currentplayernum;
playerview_t *playerview;
// int currentplayernum;
float time;
// float waterheight; //updated by the renderer. stuff sitting at this height generate ripple effects
@ -269,7 +272,7 @@ enum imageflags
/*warning: many of these flags only apply the first time it is requested*/
IF_CLAMP = 1<<0,
IF_NEAREST = 1<<1,
IF_2D = 1<<10, //subject to texturemode2d
IF_UIPIC = 1<<10, //subject to texturemode2d
IF_LINEAR = 1<<11,
IF_NOPICMIP = 1<<2,
IF_NOMIPMAP = 1<<3,

View File

@ -646,7 +646,7 @@ void Renderer_Init(void)
Cvar_Register(&scr_viewsize, SCREENOPTIONS);
Cvar_Register(&scr_fov, SCREENOPTIONS);
Cvar_Register(&scr_chatmodecvar, SCREENOPTIONS);
// Cvar_Register(&scr_chatmodecvar, SCREENOPTIONS);
Cvar_Register (&scr_sshot_type, SCREENOPTIONS);
Cvar_Register (&scr_sshot_compression, SCREENOPTIONS);
@ -880,6 +880,7 @@ rendererinfo_t dedicatedrendererinfo = {
NULL,
NULL,
NULL,
NULL,
""
};
@ -1135,8 +1136,6 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
BZ_Free(colormap);
}
R_GenPaletteLookup();
if (h2playertranslations)
BZ_Free(h2playertranslations);
h2playertranslations = FS_LoadMallocFile ("gfx/player.lmp");
@ -1145,6 +1144,7 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
vid.fullbright = 0; //transparent colour doesn't count.
q2colormap:
R_GenPaletteLookup();
TRACE(("dbg: R_ApplyRenderer: Palette loaded\n"));
@ -1499,7 +1499,7 @@ TRACE(("dbg: R_RestartRenderer_f\n"));
{
int i;
if (*vid_renderer.string)
Con_Printf("vid_renderer unsupported. Using default.\n");
Con_Printf("vid_renderer \"%s\" unsupported. Using default.\n", vid_renderer.string);
else
Con_DPrintf("vid_renderer unset. Using default.\n");
@ -1660,7 +1660,9 @@ void R_SetRenderer_f (void)
}
Cvar_Set(&vid_renderer, param);
R_RestartRenderer_f();
if (!r_blockvidrestart)
R_RestartRenderer_f();
}

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ void Sbar_Changed (void);
// call whenever any of the client stats represented on the sbar changes
qboolean Sbar_ShouldDraw(void);
void Sbar_Draw (void);
void Sbar_Draw (playerview_t *pv); //uses the current r_refdef.grect
void Sbar_DrawScoreboard (void);
// called every frame by screen

View File

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// screen.h
typedef struct playerview_s playerview_t;
extern float scr_con_current;
extern float scr_conlines; // lines of console to display
@ -53,7 +54,7 @@ void SCR_ImageName (char *mapname);
//this stuff is internal to the screen systems.
void RSpeedShow(void);
void SCR_CrosshairPosition(int pnum, int *x, int *y);
void SCR_CrosshairPosition(playerview_t *pview, int *x, int *y);
void SCR_DrawLoading (void);
void SCR_CalcRefdef (void);
void SCR_TileClear (void);
@ -113,6 +114,7 @@ void Font_InvalidateColour(void);
/*these three functions deal with formatted blocks of text (including tabs and new lines)*/
int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int maxlines, conchar_t **starts, conchar_t **ends);
int Font_LineWidth(conchar_t *start, conchar_t *end);
float Font_LineScaleWidth(conchar_t *start, conchar_t *end);
void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end);
extern struct font_s *font_conchar;
extern struct font_s *font_tiny;

View File

@ -56,12 +56,12 @@ char *Skin_FindName (player_info_t *sc)
Q_strncpyz(name, baseskin.string, sizeof(name));
}
if (cl.spectator && (tracknum = Cam_TrackNum(0)) != -1)
if (cl.spectator && (tracknum = Cam_TrackNum(&cl.playerview[0])) != -1)
skinforcing_team = cl.players[tracknum].team;
else if (cl.spectator)
skinforcing_team = "spec";
else
skinforcing_team = cl.players[cl.playernum[0]].team;
skinforcing_team = cl.players[cl.playerview[0].playernum].team;
//Don't force skins in splitscreen (it's probable that the new skin would be wrong).
//Don't force skins in TF (where skins are forced on a class basis by the mod).

View File

@ -67,7 +67,7 @@ cvar_t volume = CVARFD( "volume", "0.7", CVAR_ARCHIVE,
"Main volume level for all engine sound.");
cvar_t nosound = CVARFD( "nosound", "0", CVAR_ARCHIVE,
"Disable all sound from the engine.");
"Disable all sound from the engine. Cannot be overriden by configs or anything if set via the -nosound commandline argument.");
cvar_t precache = CVARAF( "s_precache", "1",
"precache", 0);
cvar_t loadas8bit = CVARAFD( "s_loadas8bit", "0",
@ -81,8 +81,8 @@ cvar_t snd_noextraupdate = CVARAF( "s_noextraupdate", "0",
"snd_noextraupdate", 0);
cvar_t snd_show = CVARAF( "s_show", "0",
"snd_show", 0);
cvar_t snd_khz = CVARAFD( "s_khz", "44",
"snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48.");
cvar_t snd_khz = CVARAFD( "s_khz", "48",
"snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48. Values above 1000 are explicitly in hertz.");
cvar_t snd_inactive = CVARAFD( "s_inactive", "0",
"snd_inactive", 0,
"Play sound while application is inactive (ex. tabbed out). Needs a snd_restart if changed."
@ -664,7 +664,7 @@ void S_Voip_Parse(void)
//if testing, don't get confused if the server is echoing voice too!
if (cl_voip_test.ival)
if (sender == cl.playernum[0])
if (sender == cl.playerview[0].playernum)
return;
S_Voip_Decode(sender, codec, gen, seq, bytes, data);
@ -976,11 +976,11 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
}
if (cl_voip_test.ival)
S_Voip_Decode(cl.playernum[0], s_voip.enccodec, s_voip.generation & 0x0f, initseq, outpos, outbuf);
S_Voip_Decode(cl.playerview[0].playernum, s_voip.enccodec, s_voip.generation & 0x0f, initseq, outpos, outbuf);
//update our own lastspoke, so queries shows that we're speaking when we're speaking in a generic way, even if we can't hear ourselves.
//but don't update general lastspoke, so ducking applies only when others speak. use capturingvol for yourself. they're more explicit that way.
s_voip.lastspoke[cl.playernum[0]] = realtime + 0.5;
s_voip.lastspoke[cl.playerview[0].playernum] = realtime + 0.5;
}
/*remove sent data*/
@ -1794,7 +1794,7 @@ channel_t *SND_PickChannel(soundcardinfo_t *sc, int entnum, int entchannel)
}
// don't let monster sounds override player sounds
if (sc->channel[ch_idx].entnum == cl.playernum[0]+1 && entnum != cl.playernum[0]+1 && sc->channel[ch_idx].sfx)
if (sc->channel[ch_idx].entnum == cl.playerview[0].playernum+1 && entnum != cl.playerview[0].playernum+1 && sc->channel[ch_idx].sfx)
continue;
if (!sc->channel[ch_idx].sfx)
@ -1843,7 +1843,7 @@ void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch)
}
return;
}
if (ch->entnum == -1 || ch->entnum == cl.playernum[0]+1)
if (ch->entnum == -1 || ch->entnum == cl.playerview[0].playernum+1)
{
v = ch->master_vol * (ruleset_allow_localvolume.value ? snd_playersoundvolume.value : 1) * volume.value * voicevolumemod;
v = bound(0, v, 255);
@ -2578,7 +2578,7 @@ void S_Play(void)
else
Q_strncpyz(name, Cmd_Argv(i), sizeof(name));
sfx = S_PrecacheSound(name);
S_StartSound(cl.playernum[0]+1, -1, sfx, vec3_origin, 1.0, 0.0, 0, 0);
S_StartSound(cl.playerview[0].playernum+1, -1, sfx, vec3_origin, 1.0, 0.0, 0, 0);
i++;
}
}
@ -2602,7 +2602,7 @@ void S_PlayVol(void)
Q_strncpy(name, Cmd_Argv(i), sizeof(name));
sfx = S_PrecacheSound(name);
vol = Q_atof(Cmd_Argv(i+1));
S_StartSound(cl.playernum[0]+1, -1, sfx, vec3_origin, vol, 0.0, 0, 0);
S_StartSound(cl.playerview[0].playernum+1, -1, sfx, vec3_origin, vol, 0.0, 0, 0);
i+=2;
}
}

View File

@ -799,6 +799,7 @@ struct
{"Software\\MozillaPlugins\\@fteqw.com/FTE\\Vendor", DISTRIBUTIONLONG},
{"Software\\MozillaPlugins\\@fteqw.com/FTE\\Version", "***VERSION***"},
{"Software\\MozillaPlugins\\@fteqw.com/FTE\\MimeTypes\\application/x-fteplugin\\Description", "FTE Game Engine Plugin"},
{"Software\\MozillaPlugins\\@fteqw.com/FTE\\MimeTypes\\application/x-ftemanifest\\Description", "FTE Game File Manifest Listing"},
{"Software\\MozillaPlugins\\@fteqw.com/FTE\\MimeTypes\\application/x-qtv\\Description", "QuakeTV Stream Information File"},
{"Software\\MozillaPlugins\\@fteqw.com/FTE\\MimeTypes\\application/x-qtv\\Suffixes", "qtv"},
{"Software\\MozillaPlugins\\@fteqw.com/FTE\\Suffixes\\qtv", ""},

View File

@ -158,9 +158,19 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_newglcontext(JNIEnv *env, j
//fixme: wipe image handles
}
//called when the user tries to use us to open one of our file types
JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_openfile(JNIEnv *env, jobject obj,
jstring openfile)
{
const char *fname = (*env)->GetStringUTFChars(env, openfile, NULL);
Host_RunFile(fname);
Host_Frame
(*env)->ReleaseStringUTFChars(env, openfile, fname);
}
//called for init or resizes
JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject obj,
jint width, jint height, jint glesversion, jstring japkpath, jstring jusrpath)
jint width, jint height, jint glesversion, jstring japkpath, jstring jusrpath)
{
const char *tmp;

View File

@ -1075,6 +1075,8 @@ int Plug_GenCommandline(struct context *ctx, char **argv, int maxargs)
ADDRARG("-addbasegame");
ADDCARG(tok);
}
//make sure we always use the home directory. because its better than using some random browser-defined working directory.
ADDRARG("-usehome");
if (ctx->datadownload)
{

View File

@ -36,9 +36,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <process.h>
#endif
#include "fs.h"
#ifdef GLQUAKE
#if defined(GLQUAKE) && defined(DEBUG)
#define PRINTGLARRAYS
#endif
@ -61,8 +59,6 @@ unsigned int sys_parenttop;
unsigned int sys_parentwidth; //valid if sys_parentwindow is set
unsigned int sys_parentheight;
extern int fs_switchgame;
//used to do special things with awkward windows versions.
int qwinvermaj;
int qwinvermin;
@ -265,188 +261,7 @@ typedef BOOL (WINAPI *MINIDUMPWRITEDUMP) (
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
#ifdef PRINTGLARRAYS
#include "glquake.h"
#define GL_VERTEX_ARRAY_BINDING 0x85B5
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
#define GL_CURRENT_PROGRAM 0x8B8D
char *DecodeGLEnum(GLenum num)
{
switch(num)
{
case GL_CW: return "GL_CW";
case GL_CCW: return "GL_CCW";
case GL_NEVER: return "GL_NEVER";
case GL_LESS: return "GL_LESS";
case GL_EQUAL: return "GL_EQUAL";
case GL_LEQUAL: return "GL_LEQUAL";
case GL_GREATER: return "GL_GREATER";
case GL_NOTEQUAL: return "GL_NOTEQUAL";
case GL_GEQUAL: return "GL_GEQUAL";
case GL_ALWAYS: return "GL_ALWAYS";
case GL_FRONT: return "GL_FRONT";
case GL_BACK: return "GL_BACK";
case GL_FRONT_AND_BACK: return "GL_FRONT_AND_BACK";
case GL_COMBINE_ARB: return "GL_COMBINE";
case GL_MODULATE: return "GL_MODULATE";
case GL_REPLACE: return "GL_REPLACE";
case GL_ZERO: return "GL_ZERO";
case GL_ONE: return "GL_ONE";
case GL_SRC_COLOR: return "GL_SRC_COLOR";
case GL_ONE_MINUS_SRC_COLOR: return "GL_ONE_MINUS_SRC_COLOR";
case GL_SRC_ALPHA: return "GL_SRC_ALPHA";
case GL_ONE_MINUS_SRC_ALPHA: return "GL_ONE_MINUS_SRC_ALPHA";
case GL_DST_ALPHA: return "GL_DST_ALPHA";
case GL_ONE_MINUS_DST_ALPHA: return "GL_ONE_MINUS_DST_ALPHA";
case GL_DST_COLOR: return "GL_DST_COLOR";
case GL_ONE_MINUS_DST_COLOR: return "GL_ONE_MINUS_DST_COLOR";
case GL_SRC_ALPHA_SATURATE: return "GL_SRC_ALPHA_SATURATE";
default: return va("0x%x", num);
}
}
void DumpGLState(void)
{
int rval;
void *ptr;
int i;
GLint glint;
GLint glint4[4];
void (APIENTRY *qglGetVertexAttribiv) (GLuint index, GLenum pname, GLint* params);
void (APIENTRY *qglGetVertexAttribPointerv) (GLuint index, GLenum pname, GLvoid** pointer);
qglGetVertexAttribiv = (void*)wglGetProcAddress("glGetVertexAttribiv");
qglGetVertexAttribPointerv = (void*)wglGetProcAddress("glGetVertexAttribPointerv");
#pragma comment(lib,"opengl32.lib")
if (qglGetVertexAttribiv)
{
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &rval);
Sys_Printf("VERTEX_ARRAY_BINDING: %i\n", rval);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &rval);
Sys_Printf("GL_ARRAY_BUFFER_BINDING: %i\n", rval);
if (glIsEnabled(GL_COLOR_ARRAY))
{
glGetIntegerv(GL_COLOR_ARRAY_BUFFER_BINDING, &rval);
glGetPointerv(GL_COLOR_ARRAY_POINTER, &ptr);
Sys_Printf("GL_COLOR_ARRAY: %s %i:%p\n", glIsEnabled(GL_COLOR_ARRAY)?"en":"dis", rval, ptr);
}
// if (glIsEnabled(GL_FOG_COORDINATE_ARRAY_EXT))
// {
// glGetPointerv(GL_FOG_COORD_ARRAY_POINTER, &ptr);
// Sys_Printf("GL_FOG_COORDINATE_ARRAY_EXT: %i (%lx)\n", (int) glIsEnabled(GL_FOG_COORDINATE_ARRAY_EXT), (int) ptr);
// }
// if (glIsEnabled(GL_INDEX_ARRAY))
{
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &rval);
glGetPointerv(GL_INDEX_ARRAY_POINTER, &ptr);
Sys_Printf("GL_INDEX_ARRAY: %s %i:%p\n", glIsEnabled(GL_INDEX_ARRAY)?"en":"dis", rval, ptr);
}
if (glIsEnabled(GL_NORMAL_ARRAY))
{
glGetIntegerv(GL_NORMAL_ARRAY_BUFFER_BINDING, &rval);
glGetPointerv(GL_NORMAL_ARRAY_POINTER, &ptr);
Sys_Printf("GL_NORMAL_ARRAY: %s %i:%p\n", glIsEnabled(GL_NORMAL_ARRAY)?"en":"dis", rval, ptr);
}
// glGetPointerv(GL_SECONDARY_COLOR_ARRAY_POINTER, &ptr);
// Sys_Printf("GL_SECONDARY_COLOR_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_SECONDARY_COLOR_ARRAY), (int) ptr);
for (i = 0; i < 4; i++)
{
qglClientActiveTextureARB(mtexid0 + i);
if (glIsEnabled(GL_TEXTURE_COORD_ARRAY))
{
glGetIntegerv(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &rval);
glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &ptr);
Sys_Printf("GL_TEXTURE_COORD_ARRAY %i: %s %i:%p\n", i, glIsEnabled(GL_TEXTURE_COORD_ARRAY)?"en":"dis", rval, ptr);
}
}
if (glIsEnabled(GL_VERTEX_ARRAY))
{
glGetIntegerv(GL_VERTEX_ARRAY_BUFFER_BINDING, &rval);
glGetPointerv(GL_VERTEX_ARRAY_POINTER, &ptr);
Sys_Printf("GL_VERTEX_ARRAY: %s %i:%p\n", glIsEnabled(GL_VERTEX_ARRAY)?"en":"dis", rval, ptr);
}
for (i = 0; i < 16; i++)
{
int en, bo, as, st, ty, no;
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &en);
if (!en)
continue;
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &bo);
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &as);
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &st);
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &ty);
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &no);
qglGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr);
Sys_Printf("attrib%i: %s as:%i st:%i ty:%0x %s%i:%p\n", i, en?"en":"dis", as, st,ty,no?"norm ":"", bo, ptr);
}
glGetIntegerv(GL_CURRENT_PROGRAM, &glint);
Sys_Printf("GL_CURRENT_PROGRAM: %i\n", glint);
glGetIntegerv(GL_BLEND, &glint);
Sys_Printf("GL_BLEND: %i\n", glint);
glGetIntegerv(GL_BLEND_SRC, &glint);
Sys_Printf("GL_BLEND_SRC: %i\n", DecodeGLEnum(glint));
glGetIntegerv(GL_BLEND_DST, &glint);
Sys_Printf("GL_BLEND_DST: %i\n", DecodeGLEnum(glint));
glGetIntegerv(GL_DEPTH_WRITEMASK, &glint);
Sys_Printf("GL_DEPTH_WRITEMASK: %i\n", glint);
glGetIntegerv(GL_DEPTH_TEST, &glint);
Sys_Printf("GL_DEPTH_TEST: %i\n", glint);
glGetIntegerv(GL_DEPTH_FUNC, &glint);
Sys_Printf("GL_DEPTH_FUNC: %s\n", DecodeGLEnum(glint));
glGetIntegerv(GL_CULL_FACE, &glint);
Sys_Printf("GL_CULL_FACE: %i\n", glint);
glGetIntegerv(GL_CULL_FACE_MODE, &glint);
Sys_Printf("GL_CULL_FACE_MODE: %s\n", DecodeGLEnum(glint));
glGetIntegerv(GL_FRONT_FACE, &glint);
Sys_Printf("GL_FRONT_FACE: %s\n", DecodeGLEnum(glint));
glGetIntegerv(GL_SCISSOR_TEST, &glint);
Sys_Printf("GL_SCISSOR_TEST: %i\n", glint);
glGetIntegerv(GL_STENCIL_TEST, &glint);
Sys_Printf("GL_STENCIL_TEST: %i\n", glint);
glGetIntegerv(GL_COLOR_WRITEMASK, glint4);
Sys_Printf("GL_COLOR_WRITEMASK: %i %i %i %i\n", glint4[0], glint4[1], glint4[2], glint4[3]);
GL_SelectTexture(0);
glGetIntegerv(GL_TEXTURE_2D, &glint);
Sys_Printf("GL_TEXTURE_2D: %i\n", glint);
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &glint);
Sys_Printf("GL_TEXTURE_ENV_MODE: %s\n", DecodeGLEnum(glint));
GL_SelectTexture(1);
glGetIntegerv(GL_TEXTURE_2D, &glint);
Sys_Printf("GL_TEXTURE_2D: %i\n", glint);
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &glint);
Sys_Printf("GL_TEXTURE_ENV_MODE: %s\n", DecodeGLEnum(glint));
GL_SelectTexture(2);
glGetIntegerv(GL_TEXTURE_2D, &glint);
Sys_Printf("GL_TEXTURE_2D: %i\n", glint);
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &glint);
Sys_Printf("GL_TEXTURE_ENV_MODE: %s\n", DecodeGLEnum(glint));
}
}
#endif
void DumpGLState(void);
DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTION_POINTERS exceptionInfo)
{
char dumpPath[1024];
@ -1408,7 +1223,7 @@ char *Sys_ConsoleInput (void)
{
wchar_t wch = ch;
WriteConsoleW(houtput, &wch, 1, &dummy, NULL);
len += 1;
len += utf8_encode(text+len, ch, sizeof(text)-1-len);
}
break;
@ -2455,109 +2270,6 @@ void VARGS Signal_Error_Handler(int i)
#endif
*/
qboolean Sys_RunFile(const char *fname, int nlen)
{
char buffer[MAX_OSPATH];
char *ext;
if (nlen >= MAX_OSPATH)
{
Con_Printf("Filename too long.\n");
return true;
}
memcpy(buffer, fname, nlen);
buffer[nlen] = 0;
fname = buffer;
ext = COM_FileExtension(fname);
if (!strncmp(fname, "qw:", 3))
{
fname += 3;
if (!strncmp(fname, "//", 2))
fname += 2;
ext = strchr(fname, '/'); //this also protects us against irc urls, etc. unsure if that's important right now.
if (ext)
*ext = 0;
Con_Printf("QW stream: \"%s\"\n", fname);
Cbuf_AddText(va("connect \"%s\"\n", fname), RESTRICT_LOCAL);
}
else if (!strcmp(ext, "qwd") || !strcmp(ext, "dem") || !strcmp(ext, "mvd"))
Cbuf_AddText(va("playdemo \"#%s\"\n", fname), RESTRICT_LOCAL);
else if (!strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4"))
Con_Printf("Unable to install paks/pk3s at this time\n");
else if (!strcmp(ext, "bsp"))
{
char qname[MAX_QPATH];
vfsfile_t *sf, *qf;
qboolean overwrite = false;
COM_StripExtension(COM_SkipPath(fname), qname, sizeof(qname));
sf = VFSOS_Open(fname, "rb");
qf = FS_OpenVFS(va("maps/%s.bsp", qname), "rb", FS_GAME);
if (qf)
{
if (VFS_GETLEN(sf) != VFS_GETLEN(qf))
overwrite = true;
VFS_SEEK(sf, 0);
VFS_CLOSE(qf);
}
if (overwrite)
{
switch(MessageBox(mainwindow, va("Overwrite existing map: %s?", qname), "Install And Play", MB_YESNOCANCEL))
{
case IDYES:
//overwrite it and load it up
overwrite = true;
break;
case IDNO:
//load up the old version
overwrite = false;
break;
default:
case IDCANCEL:
//quit or something
return false;
}
}
else if (!qf)
{
switch(MessageBox(mainwindow, va("Install new map: %s?", qname), "Install And Play", MB_OKCANCEL))
{
case IDOK:
//overwrite it and load it up
overwrite = true;
break;
default:
case IDCANCEL:
//quit or something
return false;
}
}
if (overwrite)
{
char buffer[8192];
int len;
qf = FS_OpenVFS(va("maps/%s.bsp", qname), "wb", FS_GAMEONLY);
if (qf)
{
while(1)
{
len = VFS_READ(sf, buffer, sizeof(buffer));
if (len <= 0)
break;
VFS_WRITE(qf, buffer, len);
}
VFS_CLOSE(qf);
}
}
VFS_CLOSE(sf);
Cbuf_AddText(va("map \"%s\"\n", qname), RESTRICT_LOCAL);
}
else
Cbuf_AddText(va("qtvplay \"#%s\"\n", fname), RESTRICT_LOCAL);
return true;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// MSG msg;
@ -2830,7 +2542,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
if (qtvfile)
{
if (!Sys_RunFile(qtvfile, strlen(qtvfile)))
if (!Host_RunFile(qtvfile, strlen(qtvfile), NULL))
{
SetHookState(false);
Host_Shutdown ();
@ -2892,20 +2604,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
Sys_Error("wut?");
#endif
}
#ifndef SERVERONLY
if (fs_switchgame != -1)
{
SetHookState(false);
Host_Shutdown ();
COM_InitArgv (parms.argc, parms.argv);
if (!Sys_Startup_CheckMem(&parms))
return 0;
Host_Init (&parms);
}
#endif
}
}
#ifdef CATCHCRASH

View File

@ -191,8 +191,11 @@ static void CloseEditor(void)
if (key_dest == key_editor)
key_dest = editor_oldkeydest;
if (key_dest == key_editor)
key_dest = key_game;
editoractive = false;
editprogfuncs = NULL;
cursorblock = NULL;
if (!firstblock)
return;
@ -686,6 +689,7 @@ void Editor_Key(int key, int unicode)
if (editprogfuncs)
editprogfuncs->AbortStack(editprogfuncs);
CloseEditor();
editormodal = false;
break;
case K_HOME:

View File

@ -107,7 +107,7 @@ static void Validation_Version(void)
{
signed_buffer_t *resp;
resp = Security_Generate_Crc(cl.playernum[0], cl.players[cl.playernum[0]].userinfo, cl.serverinfo);
resp = Security_Generate_Crc(cl.playerview[0].playernum, cl.players[cl.playerview[0].playernum].userinfo, cl.serverinfo);
if (!resp || !resp->buf)
auth = "";
else
@ -273,7 +273,7 @@ void Validation_IncludeFile(char *filename, char *file, int filelen)
static void Validation_FilesModified (void)
{
Con_Printf ("Not implemented\n");
Con_Printf ("f_modified not implemented\n");
}
void Validation_FlushFileList(void)
@ -446,12 +446,6 @@ qboolean Validation_GetCurrentRulesetName(char *rsnames, int resultbuflen, qbool
rs = rulesets;
*rsnames = '\0';
#ifdef warningmsg
#pragma warningmsg("here's a question... Should we latch the ruleset unconditionally, or only when someone actually cares?")
#pragma warningmsg("if we do it only when someone checks, we have a lot more checking, otherwise we have a freer tournament if the users choose to play that way")
#pragma warningmsg("I'm going to do it the old-fashioned way")
#pragma warningmsg("(yes, this is one for molgrum to resolve!)")
#endif
for (rs = rulesets; rs->rulesetname; rs++)
{
rs->flagged = false;
@ -517,7 +511,7 @@ void Validation_AllChecks(void)
char servername[22];
char playername[16];
char *enginebuild = version_string();
char localpnamelen = strlen(cl.players[cl.playernum[0]].name);
char localpnamelen = strlen(cl.players[cl.playerview[0].playernum].name);
char ruleset[1024];
//figure out the padding for the player's name.

View File

@ -46,7 +46,6 @@ extern rendererstate_t currentrendererstate;
typedef struct vrect_s
{
int x,y,width,height;
// struct vrect_s *pnext;
} vrect_t;
typedef struct
@ -56,7 +55,6 @@ typedef struct
unsigned width; /*virtual 2d width*/
unsigned height; /*virtual 2d height*/
int numpages;
int recalc_refdef; // if true, recalc vid-based stuff
unsigned rotpixelwidth; /*width after rotation in pixels*/
unsigned rotpixelheight; /*pixel after rotation in pixels*/

View File

@ -97,8 +97,6 @@ cvar_t scr_autoid = SCVAR("scr_autoid", "1");
extern cvar_t cl_chasecam;
float v_dmg_time[MAX_SPLITS], v_dmg_roll[MAX_SPLITS], v_dmg_pitch[MAX_SPLITS];
player_state_t *view_message;
/*
@ -137,25 +135,25 @@ V_CalcBob
===============
*/
float V_CalcBob (int pnum, qboolean queryold)
float V_CalcBob (playerview_t *pv, qboolean queryold)
{
static double bobtime[MAX_SPLITS];
static double cltime[MAX_SPLITS];
static float bob[MAX_SPLITS];
float cycle;
if (cl.spectator)
return 0;
if (!cl.onground[pnum] || cl.paused)
return bob[pnum]; // just use old value
if (!pv->onground || cl.paused)
{
pv->bobcltime = cl.time;
return pv->bob; // just use old value
}
if (cl_bobcycle.value <= 0)
return 0;
bobtime[pnum] += cl.time - cltime[pnum];
cltime[pnum] = cl.time;
cycle = bobtime[pnum] - (int)(bobtime[pnum]/cl_bobcycle.value)*cl_bobcycle.value;
pv->bobtime += cl.time - pv->bobcltime;
pv->bobcltime = cl.time;
cycle = pv->bobtime - (int)(pv->bobtime/cl_bobcycle.value)*cl_bobcycle.value;
cycle /= cl_bobcycle.value;
if (cycle < cl_bobup.value)
cycle = M_PI * cycle / cl_bobup.value;
@ -164,14 +162,15 @@ float V_CalcBob (int pnum, qboolean queryold)
// bob is proportional to simulated velocity in the xy plane
// (don't count Z, or jumping messes it up)
//FIXME: gravitydir
bob[pnum] = sqrt(cl.playerview[pnum].simvel[0]*cl.playerview[pnum].simvel[0] + cl.playerview[pnum].simvel[1]*cl.playerview[pnum].simvel[1]) * cl_bob.value;
bob[pnum] = bob[pnum]*0.3 + bob[pnum]*0.7*sin(cycle);
if (bob[pnum] > 4)
bob[pnum] = 4;
else if (bob[pnum] < -7)
bob[pnum] = -7;
return bob[pnum];
pv->bob = sqrt(pv->simvel[0]*pv->simvel[0] + pv->simvel[1]*pv->simvel[1]) * cl_bob.value;
pv->bob = pv->bob*0.3 + pv->bob*0.7*sin(cycle);
if (pv->bob > 4)
pv->bob = 4;
else if (pv->bob < -7)
pv->bob = -7;
return pv->bob;
}
@ -183,27 +182,27 @@ cvar_t v_centermove = SCVAR("v_centermove", "0.15");
cvar_t v_centerspeed = SCVAR("v_centerspeed","500");
void V_StartPitchDrift (int pnum)
void V_StartPitchDrift (playerview_t *pv)
{
#if 1
if (cl.playerview[pnum].laststop == cl.time)
if (pv->laststop == cl.time)
{
return; // something else is keeping it from drifting
}
#endif
if (cl.playerview[pnum].nodrift || !cl.playerview[pnum].pitchvel)
if (pv->nodrift || !pv->pitchvel)
{
cl.playerview[pnum].pitchvel = v_centerspeed.value;
cl.playerview[pnum].nodrift = false;
cl.playerview[pnum].driftmove = 0;
pv->pitchvel = v_centerspeed.value;
pv->nodrift = false;
pv->driftmove = 0;
}
}
void V_StopPitchDrift (int pnum)
void V_StopPitchDrift (playerview_t *pv)
{
cl.playerview[pnum].laststop = cl.time;
cl.playerview[pnum].nodrift = true;
cl.playerview[pnum].pitchvel = 0;
pv->laststop = cl.time;
pv->nodrift = true;
pv->pitchvel = 0;
}
/*
@ -219,42 +218,42 @@ Drifting is enabled when the center view key is hit, mlook is released and
lookspring is non 0, or when
===============
*/
void V_DriftPitch (int pnum)
void V_DriftPitch (playerview_t *pv)
{
float delta, move;
if (!cl.onground || cls.demoplayback )
if (!pv->onground || cls.demoplayback )
{
cl.playerview[pnum].driftmove = 0;
cl.playerview[pnum].pitchvel = 0;
pv->driftmove = 0;
pv->pitchvel = 0;
return;
}
// don't count small mouse motion
if (cl.playerview[pnum].nodrift)
if (pv->nodrift)
{
if ( fabs(cl.outframes[(cl.movesequence-1)&UPDATE_MASK].cmd[pnum].forwardmove) < 200)
cl.playerview[pnum].driftmove = 0;
if (Length(pv->simvel) < 200)
pv->driftmove = 0;
else
cl.playerview[pnum].driftmove += host_frametime;
pv->driftmove += host_frametime;
if ( cl.playerview[pnum].driftmove > v_centermove.value)
if ( pv->driftmove > v_centermove.value)
{
V_StartPitchDrift (pnum);
V_StartPitchDrift (pv);
}
return;
}
delta = 0 - cl.playerview[pnum].viewangles[PITCH];
delta = 0 - pv->viewangles[PITCH];
if (!delta)
{
cl.playerview[pnum].pitchvel = 0;
pv->pitchvel = 0;
return;
}
move = host_frametime * cl.playerview[pnum].pitchvel;
cl.playerview[pnum].pitchvel += host_frametime * v_centerspeed.value;
move = host_frametime * pv->pitchvel;
pv->pitchvel += host_frametime * v_centerspeed.value;
//Con_Printf ("move: %f (%f)\n", move, host_frametime);
@ -262,19 +261,19 @@ void V_DriftPitch (int pnum)
{
if (move > delta)
{
cl.playerview[pnum].pitchvel = 0;
pv->pitchvel = 0;
move = delta;
}
cl.playerview[pnum].viewangles[PITCH] += move;
pv->viewangles[PITCH] += move;
}
else if (delta < 0)
{
if (move > -delta)
{
cl.playerview[pnum].pitchvel = 0;
pv->pitchvel = 0;
move = -delta;
}
cl.playerview[pnum].viewangles[PITCH] -= move;
pv->viewangles[PITCH] -= move;
}
}
@ -366,7 +365,6 @@ V_CheckGamma
void GLV_Gamma_Callback(struct cvar_s *var, char *oldvalue)
{
BuildGammaTable (v_gamma.value, v_contrast.value, v_brightness.value);
vid.recalc_refdef = 1; // force a surface cache flush
V_UpdatePalette (true);
}
#endif
@ -376,7 +374,7 @@ void GLV_Gamma_Callback(struct cvar_s *var, char *oldvalue)
V_ParseDamage
===============
*/
void V_ParseDamage (int pnum)
void V_ParseDamage (playerview_t *pv)
{
int armor, blood;
vec3_t from;
@ -401,7 +399,7 @@ void V_ParseDamage (int pnum)
if (v_damagecshift.value >= 0)
count *= v_damagecshift.value;
cl.playerview[pnum].faceanimtime = cl.time + 0.2; // but sbar face into pain frame
pv->faceanimtime = cl.time + 0.2; // but sbar face into pain frame
cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
@ -431,18 +429,18 @@ void V_ParseDamage (int pnum)
//
// calculate view angle kicks
//
VectorSubtract (from, cl.playerview[pnum].simorg, from);
VectorSubtract (from, pv->simorg, from);
VectorNormalize (from);
AngleVectors (cl.playerview[pnum].simangles, forward, right, up);
AngleVectors (pv->simangles, forward, right, up);
side = DotProduct (from, right);
v_dmg_roll[pnum] = count*side*v_kickroll.value;
pv->v_dmg_roll = count*side*v_kickroll.value;
side = DotProduct (from, forward);
v_dmg_pitch[pnum] = count*side*v_kickpitch.value;
pv->v_dmg_pitch = count*side*v_kickpitch.value;
v_dmg_time[pnum] = v_kicktime.value;
pv->v_dmg_time = v_kicktime.value;
}
@ -802,7 +800,7 @@ float angledelta (float a)
CalcGunAngle
==================
*/
void V_CalcGunPositionAngle (int pnum, float bob)
void V_CalcGunPositionAngle (playerview_t *pv, float bob)
{
float yaw, pitch, move;
static float oldyaw = 0;
@ -848,37 +846,37 @@ void V_CalcGunPositionAngle (int pnum, float bob)
oldyaw = yaw;
oldpitch = pitch;
cl.viewent[pnum].angles[YAW] = r_refdef.viewangles[YAW] + yaw;
cl.viewent[pnum].angles[PITCH] = r_refdef.viewangles[PITCH] + pitch;
pv->viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
pv->viewent.angles[PITCH] = r_refdef.viewangles[PITCH] + pitch;
cl.viewent[pnum].angles[YAW] = r_refdef.viewangles[YAW];
cl.viewent[pnum].angles[PITCH] = r_refdef.viewangles[PITCH];
cl.viewent[pnum].angles[ROLL] = r_refdef.viewangles[ROLL];
pv->viewent.angles[YAW] = r_refdef.viewangles[YAW];
pv->viewent.angles[PITCH] = r_refdef.viewangles[PITCH];
pv->viewent.angles[ROLL] = r_refdef.viewangles[ROLL];
AngleVectors(cl.viewent[pnum].angles, cl.viewent[pnum].axis[0], cl.viewent[pnum].axis[1], cl.viewent[pnum].axis[2]);
VectorInverse(cl.viewent[pnum].axis[1]);
cl.viewent[pnum].angles[PITCH]*=-1;
AngleVectors(pv->viewent.angles, pv->viewent.axis[0], pv->viewent.axis[1], pv->viewent.axis[2]);
VectorInverse(pv->viewent.axis[1]);
pv->viewent.angles[PITCH]*=-1;
VectorCopy (r_refdef.vieworg, cl.viewent[pnum].origin);
VectorCopy (r_refdef.vieworg, pv->viewent.origin);
for (i=0 ; i<3 ; i++)
{
cl.viewent[pnum].origin[i] += cl.viewent[pnum].axis[0][i]*bob*0.4;
// cl.viewent[pnum].origin[i] += cl.viewent[pnum].axis[1][i]*sin(cl.time*5.5342452354235)*0.1;
// cl.viewent[pnum].origin[i] += cl.viewent[pnum].axis[2][i]*bob*0.8;
pv->viewent.origin[i] += pv->viewent.axis[0][i]*bob*0.4;
// pv->viewent.origin[i] += pv->viewent.axis[1][i]*sin(cl.time*5.5342452354235)*0.1;
// pv->viewent.origin[i] += pv->viewent.axis[2][i]*bob*0.8;
}
// fudge position around to keep amount of weapon visible
// roughly equal with different FOV
if (scr_viewsize.value == 110)
cl.viewent[pnum].origin[2] += 1;
pv->viewent.origin[2] += 1;
else if (scr_viewsize.value == 100)
cl.viewent[pnum].origin[2] += 2;
pv->viewent.origin[2] += 2;
else if (scr_viewsize.value == 90)
cl.viewent[pnum].origin[2] += 1;
pv->viewent.origin[2] += 1;
else if (scr_viewsize.value == 80)
cl.viewent[pnum].origin[2] += 0.5;
pv->viewent.origin[2] += 0.5;
}
/*
@ -912,7 +910,7 @@ V_AddIdle
Idle swaying
==============
*/
void V_AddIdle (int pnum)
void V_AddIdle (playerview_t *pv)
{
//defaults: for use if idlescale is locked and the var isn't.
float yaw_cycle = 2;
@ -940,9 +938,9 @@ void V_AddIdle (int pnum)
r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*pitch_cycle) * pitch_level;
r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*yaw_cycle) * yaw_level;
cl.viewent[pnum].angles[ROLL] -= v_idlescale.value * sin(cl.time*roll_cycle) * roll_level;
cl.viewent[pnum].angles[PITCH] -= v_idlescale.value * sin(cl.time*pitch_cycle) * pitch_level;
cl.viewent[pnum].angles[YAW] -= v_idlescale.value * sin(cl.time*yaw_cycle) * yaw_level;
pv->viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*roll_cycle) * roll_level;
pv->viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*pitch_cycle) * pitch_level;
pv->viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*yaw_cycle) * yaw_level;
}
@ -953,12 +951,12 @@ V_CalcViewRoll
Roll is induced by movement and damage
==============
*/
void V_CalcViewRoll (int pnum)
void V_CalcViewRoll (playerview_t *pv)
{
float side;
float adjspeed;
side = V_CalcRoll (cl.playerview[pnum].simangles, cl.playerview[pnum].simvel);
side = V_CalcRoll (pv->simangles, pv->simvel);
adjspeed = fabs(cl_rollangle.value);
if (adjspeed<1)
@ -966,25 +964,25 @@ void V_CalcViewRoll (int pnum)
if (adjspeed>45)
adjspeed = 45;
adjspeed*=20;
if (side > cl.playerview[pnum].rollangle)
if (side > pv->rollangle)
{
cl.playerview[pnum].rollangle += host_frametime * adjspeed;
if (cl.playerview[pnum].rollangle > side)
cl.playerview[pnum].rollangle = side;
pv->rollangle += host_frametime * adjspeed;
if (pv->rollangle > side)
pv->rollangle = side;
}
else if (side < cl.playerview[pnum].rollangle)
else if (side < pv->rollangle)
{
cl.playerview[pnum].rollangle -= host_frametime * adjspeed;
if (cl.playerview[pnum].rollangle < side)
cl.playerview[pnum].rollangle = side;
pv->rollangle -= host_frametime * adjspeed;
if (pv->rollangle < side)
pv->rollangle = side;
}
r_refdef.viewangles[ROLL] += cl.playerview[pnum].rollangle;
r_refdef.viewangles[ROLL] += pv->rollangle;
if (v_dmg_time[pnum] > 0)
if (pv->v_dmg_time > 0)
{
r_refdef.viewangles[ROLL] += v_dmg_time[pnum]/v_kicktime.value*v_dmg_roll[pnum];
r_refdef.viewangles[PITCH] += v_dmg_time[pnum]/v_kicktime.value*v_dmg_pitch[pnum];
v_dmg_time[pnum] -= host_frametime;
r_refdef.viewangles[ROLL] += pv->v_dmg_time/v_kicktime.value*pv->v_dmg_roll;
r_refdef.viewangles[PITCH] += pv->v_dmg_time/v_kicktime.value*pv->v_dmg_pitch;
pv->v_dmg_time -= host_frametime;
}
}
@ -996,51 +994,220 @@ V_CalcIntermissionRefdef
==================
*/
void V_CalcIntermissionRefdef (int pnum)
void V_CalcIntermissionRefdef (playerview_t *pv)
{
entity_t *view;
float old;
// view is the weapon model
view = &cl.viewent[pnum];
view = &pv->viewent;
VectorCopy (cl.playerview[pnum].simorg, r_refdef.vieworg);
VectorCopy (cl.playerview[pnum].simangles, r_refdef.viewangles);
VectorCopy (pv->simorg, r_refdef.vieworg);
VectorCopy (pv->simangles, r_refdef.viewangles);
view->model = NULL;
// always idle in intermission
old = v_idlescale.value;
v_idlescale.value = 1;
V_AddIdle (pnum);
V_AddIdle (pv);
v_idlescale.value = old;
}
float CalcFov (float fov_x, float width, float height);
/*
=================
v_ApplyRefdef
called to apply any dirty refdef bits and recalculates pending data.
=================
*/
void V_ApplyRefdef (void)
{
float size;
int h;
qboolean full = false;
// force the status bar to redraw
Sbar_Changed ();
//========================================
r_refdef.flags = 0;
// intermission is always full screen
if (cl.intermission || !r_refdef.drawsbar)
size = 120;
else
size = scr_viewsize.value;
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2) //q2 never has a hud.
sb_lines = 0;
else
#endif
if (size >= 120)
sb_lines = 0; // no status bar at all
else if (size >= 110)
sb_lines = 24; // no inventory
else
sb_lines = 24+16+8;
if (scr_viewsize.value >= 100.0 || scr_chatmode)
{
full = true;
size = 100.0;
}
else
size = scr_viewsize.value;
if (cl.intermission || !r_refdef.drawsbar)
{
full = true;
size = 100.0;
sb_lines = 0;
}
size /= 100.0;
if (cl_sbar.value!=1 && full)
h = r_refdef.grect.height;
else
h = r_refdef.grect.height - sb_lines;
if (h < 0)
h = 0;
r_refdef.vrect.width = r_refdef.grect.width * size;
if (r_refdef.vrect.width < 96)
r_refdef.vrect.width = 96; // min for icons
r_refdef.vrect.height = r_refdef.grect.height * size;
if (cl_sbar.value==1 || !full)
{
if (r_refdef.vrect.height > r_refdef.grect.height - sb_lines)
r_refdef.vrect.height = r_refdef.grect.height - sb_lines;
}
else if (r_refdef.vrect.height > r_refdef.grect.height)
r_refdef.vrect.height = r_refdef.grect.height;
if (r_refdef.vrect.height < 0)
r_refdef.vrect.height = 0;
r_refdef.vrect.x = (r_refdef.grect.width - r_refdef.vrect.width)/2;
if (full)
r_refdef.vrect.y = 0;
else
r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
if (scr_chatmode)
{
if (scr_chatmode != 2)
r_refdef.vrect.height = r_refdef.vrect.y=r_refdef.grect.height/2;
r_refdef.vrect.width = r_refdef.vrect.x=r_refdef.grect.width/2;
if (r_refdef.vrect.width<320 || r_refdef.vrect.height<200) //disable hud if too small
sb_lines=0;
}
r_refdef.vrect.x += r_refdef.grect.x;
r_refdef.vrect.y += r_refdef.grect.y;
if (r_refdef.dirty & RDFD_FOV)
{
//explicit fov overrides aproximate fov.
//aproximate fov is our regular fov value. explicit is settable by gamecode for weird aspect ratios
if (!r_refdef.fov_x || !r_refdef.fov_y)
{
extern cvar_t r_stereo_method, r_stereo_separation;
float ws;
float afov = r_refdef.afov;
if (!afov) //make sure its sensible.
afov = scr_fov.value;
if (r_refdef.playerview->stats[STAT_VIEWZOOM])
afov *= r_refdef.playerview->stats[STAT_VIEWZOOM]/255.0f;
ws = 1;
if (r_stereo_method.ival == 5 && r_stereo_separation.value)
ws = 0.5;
//attempt to retain a classic fov
if (ws*r_refdef.vrect.width < (r_refdef.vrect.height*640)/432)
{
r_refdef.fov_y = CalcFov(afov, (ws*r_refdef.vrect.width*vid.pixelwidth)/vid.width, (r_refdef.vrect.height*vid.pixelheight)/vid.height);
r_refdef.fov_x = afov;//CalcFov(r_refdef.fov_y, 432, 640);
}
else
{
r_refdef.fov_y = CalcFov(afov, 640, 432);
r_refdef.fov_x = CalcFov(r_refdef.fov_y, r_refdef.vrect.height, r_refdef.vrect.width*ws);
}
}
}
r_refdef.dirty = 0;
}
//if the view entities differ, removes all externalmodel flags except for adding it to the new entity, and removes weaponmodels.
void CL_EditExternalModels(int newviewentity)
{
int i;
for (i = 0; i < cl_numvisedicts; )
{
if (cl_visedicts[i].keynum == newviewentity && newviewentity)
cl_visedicts[i].flags |= Q2RF_EXTERNALMODEL;
else
cl_visedicts[i].flags &= ~Q2RF_EXTERNALMODEL;
if (cl_visedicts[i].flags & Q2RF_WEAPONMODEL)
{
memmove(&cl_visedicts[i], &cl_visedicts[i+1], sizeof(*cl_visedicts) * (cl_numvisedicts-(i+1)));
cl_numvisedicts--;
}
else
i++;
}
}
/*
clears the refdef to defaults.
*/
void V_ClearRefdef(playerview_t *pv)
{
r_refdef.playerview = pv;
r_refdef.dirty = ~0;
r_refdef.grect.x = 0;
r_refdef.grect.y = 0;
r_refdef.grect.width = vid.width;
r_refdef.grect.height = vid.height;
r_refdef.afov = scr_fov.value; //will have a better value applied if fov is bad. this allows setting.
r_refdef.fov_x = 0;
r_refdef.fov_y = 0;
r_refdef.drawsbar = !cl.intermission;
}
/*
==================
V_CalcRefdef
==================
*/
void V_CalcRefdef (int pnum)
void V_CalcRefdef (playerview_t *pv)
{
entity_t *view;
int i;
float bob;
float viewheight;
r_refdef.currentplayernum = pnum;
r_refdef.playerview = pv;
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
return;
#endif
VectorCopy(cl.fog_colour, r_refdef.gfog_rgbd);
r_refdef.gfog_rgbd[3] = cl.fog_density / 64;
// view is the weapon model (only visible from inside body)
view = &cl.viewent[pnum];
view = &pv->viewent;
if (v_viewheight.value < -7)
bob=-7;
@ -1049,10 +1216,10 @@ void V_CalcRefdef (int pnum)
else if (v_viewheight.value)
bob=v_viewheight.value;
else
bob = V_CalcBob (pnum, false);
bob = V_CalcBob (pv, false);
// refresh position from simulated origin
VectorCopy (cl.playerview[pnum].simorg, r_refdef.vieworg);
VectorCopy (pv->simorg, r_refdef.vieworg);
r_refdef.useperspective = true;
@ -1063,9 +1230,9 @@ void V_CalcRefdef (int pnum)
r_refdef.vieworg[1] += 1.0/16;
r_refdef.vieworg[2] += 1.0/16;
if (cl.playerview[pnum].fixangle)
if (pv->fixangle)
{
if (cl.playerview[pnum].oldfixangle)
if (pv->oldfixangle)
{
float frac, move;
if (cl.gametime <= cl.oldgametime)
@ -1077,27 +1244,27 @@ void V_CalcRefdef (int pnum)
}
for (i = 0; i < 3; i++)
{
move = cl.playerview[pnum].fixangles[i] - cl.playerview[pnum].oldfixangles[i];
move = pv->fixangles[i] - pv->oldfixangles[i];
if (move >= 180)
move -= 360;
if (move <= -180)
move += 360;
r_refdef.viewangles[i] = cl.playerview[pnum].oldfixangles[i] + frac * move;
r_refdef.viewangles[i] = pv->oldfixangles[i] + frac * move;
}
}
else
{
VectorCopy (cl.playerview[pnum].fixangles, r_refdef.viewangles);
VectorCopy (pv->fixangles, r_refdef.viewangles);
}
}
else
{
VectorCopy (cl.playerview[pnum].simangles, r_refdef.viewangles);
VectorCopy (pv->simangles, r_refdef.viewangles);
}
V_CalcViewRoll (pnum);
V_AddIdle (pnum);
V_CalcViewRoll (pv);
V_AddIdle (pv);
viewheight = cl.viewheight[pnum];
viewheight = pv->viewheight;
if (viewheight == DEFAULT_VIEWHEIGHT)
{
if (view_message && view_message->flags & PF_GIB)
@ -1106,9 +1273,9 @@ void V_CalcRefdef (int pnum)
viewheight = 16; // corpse view height
}
viewheight += cl.crouch[pnum];
viewheight += pv->crouch;
if (cl.playerview[pnum].stats[STAT_HEALTH] < 0 && spec_track[pnum] >= 0 && v_deathtilt.value) // PF_GIB will also set PF_DEAD
if (pv->stats[STAT_HEALTH] < 0 && pv->cam_spec_track >= 0 && v_deathtilt.value) // PF_GIB will also set PF_DEAD
{
if (!cl.spectator || !cl_chasecam.ival)
r_refdef.viewangles[ROLL] = 80*v_deathtilt.value; // dead view angle
@ -1119,23 +1286,23 @@ void V_CalcRefdef (int pnum)
viewheight += bob;
}
VectorMA(r_refdef.vieworg, -viewheight, cl.playerview[pnum].gravitydir, r_refdef.vieworg);
VectorMA(r_refdef.vieworg, -viewheight, pv->gravitydir, r_refdef.vieworg);
// set up gun position
V_CalcGunPositionAngle (pnum, bob);
V_CalcGunPositionAngle (pv, bob);
if (cl.playerview[pnum].stats[STAT_HEALTH] > 0 && (unsigned int)cl.playerview[pnum].stats[STAT_WEAPON] >= MAX_MODELS)
if (pv->statsf[STAT_HEALTH] <= 0 || (unsigned int)pv->stats[STAT_WEAPON] >= MAX_MODELS)
view->model = NULL;
else
view->model = cl.model_precache[cl.playerview[pnum].stats[STAT_WEAPON]];
view->model = cl.model_precache[pv->stats[STAT_WEAPON]];
#ifdef HLCLIENT
if (!CLHL_AnimateViewEntity(view))
#endif
view->framestate.g[FS_REG].frame[0] = cl.playerview[pnum].stats[STAT_WEAPONFRAME];
view->framestate.g[FS_REG].frame[0] = pv->stats[STAT_WEAPONFRAME];
// set up the refresh position
if (v_gunkick.value)
r_refdef.viewangles[PITCH] += cl.punchangle[pnum]*v_gunkick.value;
r_refdef.viewangles[PITCH] += pv->punchangle*v_gunkick.value;
r_refdef.time = realtime;
@ -1153,19 +1320,19 @@ void V_CalcRefdef (int pnum)
DropPunchAngle
=============
*/
void DropPunchAngle (int pnum)
void DropPunchAngle (playerview_t *pv)
{
if (cl.punchangle[pnum] < 0)
if (pv->punchangle < 0)
{
cl.punchangle[pnum] += 10*host_frametime;
if (cl.punchangle[pnum] > 0)
cl.punchangle[pnum] = 0;
pv->punchangle += 10*host_frametime;
if (pv->punchangle > 0)
pv->punchangle = 0;
}
else
{
cl.punchangle[pnum] -= 10*host_frametime;
if (cl.punchangle[pnum] < 0)
cl.punchangle[pnum] = 0;
pv->punchangle -= 10*host_frametime;
if (pv->punchangle < 0)
pv->punchangle = 0;
}
}
@ -1199,18 +1366,16 @@ entity_t *CL_EntityNum(int num)
float CalcFov (float fov_x, float width, float height);
void SCR_VRectForPlayer(vrect_t *vrect, int pnum)
{
float ws;
extern cvar_t r_stereo_method, r_stereo_separation;
#if MAX_SPLITS > 4
#pragma warning "Please change this function to cope with the new MAX_SPLITS value"
#endif
switch(cl.splitclients)
{
case 1:
vrect->width = scr_vrect.width;
vrect->height = scr_vrect.height;
vrect->x = scr_vrect.x;
vrect->y = scr_vrect.y;
vrect->width = vid.width;
vrect->height = vid.height;
vrect->x = 0;
vrect->y = 0;
if (scr_chatmode == 2)
{
@ -1253,25 +1418,6 @@ void SCR_VRectForPlayer(vrect_t *vrect, int pnum)
default:
Sys_Error("cl.splitclients is invalid.");
}
r_refdef.fov_x = scr_fov.value;
if (cl.playerview[pnum].stats[STAT_VIEWZOOM])
r_refdef.fov_x *= cl.playerview[pnum].stats[STAT_VIEWZOOM]/255.0f;
ws = 1;
if (r_stereo_method.ival == 5 && r_stereo_separation.value)
ws = 0.5;
if (ws*vrect->width < (vrect->height*640)/432)
{
r_refdef.fov_y = CalcFov(r_refdef.fov_x, (ws*vrect->width*vid.pixelwidth)/vid.width, (vrect->height*vid.pixelheight)/vid.height);
// r_refdef.fov_x = CalcFov(r_refdef.fov_y, 432, 640);
}
else
{
r_refdef.fov_y = CalcFov(r_refdef.fov_x, 640, 432);
r_refdef.fov_x = CalcFov(r_refdef.fov_y, vrect->height, vrect->width*ws);
}
}
void Draw_ExpandedString(int x, int y, conchar_t *str);
@ -1304,11 +1450,11 @@ void R_DrawNameTags(void)
{
if (!nametagseen[i])
continue;
if (i == cl.playernum[r_refdef.currentplayernum])
if (i == r_refdef.playerview->playernum)
continue; // Don't draw tag for the local player
if (cl.players[i].spectator)
continue;
if (i == Cam_TrackNum(r_refdef.currentplayernum))
if (i == Cam_TrackNum(r_refdef.playerview))
continue;
if (TP_IsPlayerVisible(nametagorg[i]))
@ -1325,33 +1471,33 @@ void R_DrawNameTags(void)
}
void R2D_PolyBlend (void);
void V_RenderPlayerViews(int plnum)
void V_RenderPlayerViews(playerview_t *pv)
{
int oldnuments;
int oldstris;
#ifdef SIDEVIEWS
int viewnum;
#endif
SCR_VRectForPlayer(&r_refdef.vrect, plnum);
// cl.simangles[plnum][ROLL] = 0; // FIXME @@@
DropPunchAngle (pv);
DropPunchAngle (plnum);
Cam_SelfTrack(pv);
if (cl.intermission)
{ // intermission / finale rendering
V_CalcIntermissionRefdef (plnum);
V_CalcIntermissionRefdef (pv);
}
else
{
V_DriftPitch (plnum);
V_CalcRefdef (plnum);
V_DriftPitch (pv);
V_CalcRefdef (pv);
}
V_ApplyRefdef();
oldnuments = cl_numvisedicts;
oldstris = cl_numstris;
CL_LinkViewModel ();
Cam_SelfTrack(plnum);
R_RenderView ();
R2D_PolyBlend ();
R_DrawNameTags();
@ -1361,21 +1507,18 @@ void V_RenderPlayerViews(int plnum)
if (scr_chatmode == 2)
{
extern vec3_t desired_position[MAX_SPLITS];
vec3_t dir;
r_refdef.vrect.y -= r_refdef.vrect.height;
vid.recalc_refdef=true;
r_secondaryview = 2;
VectorSubtract(r_refdef.vieworg, desired_position[plnum], dir);
VectorSubtract(r_refdef.vieworg, pv->cam_desired_position, dir);
VectorAngles(dir, NULL, r_refdef.viewangles);
r_refdef.viewangles[0] = -r_refdef.viewangles[0]; //flip the pitch. :(
VectorCopy(desired_position[plnum], r_refdef.vieworg);
VectorCopy(pv->cam_desired_position, r_refdef.vieworg);
R_RenderView ();
vid.recalc_refdef=true;
}
@ -1390,7 +1533,7 @@ void V_RenderPlayerViews(int plnum)
for (viewnum = 0; viewnum < SIDEVIEWS; viewnum++)
if (vsec_scalex[viewnum].value>0&&vsec_scaley[viewnum].value>0
&& ((vsec_enabled[viewnum].value && vsec_enabled[viewnum].value != 2 && cls.allow_rearview) //rearview if v2_enabled = 1 and not 2
|| (vsec_enabled[viewnum].value && cl.playerview[plnum].stats[STAT_VIEW2]&&viewnum==0))) //v2 enabled if v2_enabled is non-zero
|| (vsec_enabled[viewnum].value && pv->stats[STAT_VIEW2]&&viewnum==0))) //v2 enabled if v2_enabled is non-zero
{
vrect_t oldrect;
vec3_t oldangles;
@ -1400,8 +1543,6 @@ void V_RenderPlayerViews(int plnum)
float ofx;
float ofy;
vid.recalc_refdef=true;
r_secondaryview = true;
if (vsec_x[viewnum].value < 0)
@ -1427,9 +1568,9 @@ void V_RenderPlayerViews(int plnum)
#ifdef PEXT_VIEW2
//secondary view entity.
e=NULL;
if (viewnum==0&&cl.playerview[plnum].stats[STAT_VIEW2])
if (viewnum==0&&pv->stats[STAT_VIEW2])
{
e = CL_EntityNum (cl.playerview[plnum].stats[STAT_VIEW2]);
e = CL_EntityNum (pv->stats[STAT_VIEW2]);
}
if (e)
{
@ -1446,7 +1587,14 @@ void V_RenderPlayerViews(int plnum)
r_refdef.viewangles[2]=e->angles[2];//*s+(1-s)*e->msg_angles[1][2];
r_refdef.viewangles[PITCH] *= -1;
r_refdef.externalview = true; //show the player
if (e->keynum >= 1 && e->keynum <= cl.allocated_client_slots)
{
r_refdef.viewangles[PITCH] *= 3;
r_refdef.vieworg[2] += pv->statsf[STAT_VIEWHEIGHT];
}
CL_EditExternalModels(e->keynum);
R_RenderView ();
// r_framecount = old_framecount;
@ -1460,6 +1608,7 @@ void V_RenderPlayerViews(int plnum)
r_refdef.viewangles[PITCH] *= -cos((vsec_yaw[viewnum].value / 180 * 3.14)+3.14);
if (vsec_enabled[viewnum].value!=2)
{
CL_EditExternalModels(0);
R_RenderView ();
}
}
@ -1469,8 +1618,6 @@ void V_RenderPlayerViews(int plnum)
memcpy(r_refdef.vieworg, oldposition, sizeof(vec3_t));
r_refdef.fov_x = ofx;
r_refdef.fov_y = ofy;
vid.recalc_refdef=true;
}
#endif
r_refdef.externalview = false;
@ -1485,31 +1632,45 @@ void V_RenderView (void)
if (cls.state != ca_active)
return;
if (r_worldentity.model)
{
RSpeedMark();
CL_AllowIndependantSendCmd(false);
CL_TransitionEntities();
CL_PredictMove ();
// build a refresh entity list
CL_EmitEntities ();
CL_AllowIndependantSendCmd(true);
RSpeedEnd(RSPEED_LINKENTITIES);
}
R_PushDlights ();
r_secondaryview = 0;
for (viewnum = 0; viewnum < cl.splitclients; viewnum++)
{
V_RenderPlayerViews(viewnum);
V_ClearRefdef(&cl.playerview[viewnum]);
if (viewnum)
{
//should be enough to just hack a few things.
CL_EditExternalModels(cl.playerview[viewnum].viewentity);
}
else
{
if (r_worldentity.model)
{
RSpeedMark();
CL_AllowIndependantSendCmd(false);
CL_TransitionEntities();
CL_PredictMove ();
// build a refresh entity list
CL_EmitEntities ();
CL_AllowIndependantSendCmd(true);
RSpeedEnd(RSPEED_LINKENTITIES);
}
}
SCR_VRectForPlayer(&r_refdef.grect, viewnum);
V_RenderPlayerViews(r_refdef.playerview);
GL_Set2D (false);
Plug_SBar(r_refdef.playerview);
SCR_TileClear ();
}
r_refdef.playerview = NULL;
}
//============================================================================

View File

@ -523,7 +523,7 @@ static char *Macro_Powerups (void)
if (cl.playerview[SP].stats[STAT_ITEMS] & IT_INVISIBILITY)
MacroBuf_strcat_with_separator (tp_name_ring.string);
effects = cl.inframes[cl.parsecount&UPDATE_MASK].playerstate[cl.playernum[SP]].effects;
effects = cl.inframes[cl.parsecount&UPDATE_MASK].playerstate[cl.playerview[SP].playernum].effects;
if ( (effects & (QWEF_FLAG1|QWEF_FLAG2)) || // CTF
(cl.teamfortress && cl.playerview[SP].stats[STAT_ITEMS] & (IT_KEY1|IT_KEY2)) ) // TF
MacroBuf_strcat_with_separator (tp_name_flag.string);
@ -716,7 +716,7 @@ static char *Skin_To_TFSkin (char *myskin)
static char *Macro_TF_Skin (void)
{
return Skin_To_TFSkin(Info_ValueForKey(cl.players[cl.playernum[0]].userinfo, "skin"));
return Skin_To_TFSkin(Info_ValueForKey(cl.players[cl.playerview[SP].playernum].userinfo, "skin"));
}
//Spike: added these:
@ -882,7 +882,7 @@ static void CountNearbyPlayers(qboolean dead)
state = cl.inframes[cl.oldparsecount & UPDATE_MASK].playerstate;
info = cl.players;
for (i = 0; i < MAX_CLIENTS; i++, info++, state++) {
if (i != cl.playernum[0] && state->messagenum == cl.oldparsecount && !info->spectator && !ISDEAD(state->frame)) {
if (i != cl.playerview[SP].playernum && state->messagenum == cl.oldparsecount && !info->spectator && !ISDEAD(state->frame)) {
if (cl.teamplay && !strcmp(info->team, TP_PlayerTeam()))
vars.numfriendlies++;
else
@ -1770,7 +1770,7 @@ int TP_CountPlayers (void)
char *TP_PlayerTeam (void)
{
return cl.players[cl.playernum[SP]].team;
return cl.players[cl.playerview[SP].playernum].team;
}
char *TP_EnemyTeam (void)
@ -1792,7 +1792,7 @@ char *TP_EnemyTeam (void)
char *TP_PlayerName (void)
{
return cl.players[cl.playernum[SP]].name;
return cl.players[cl.playerview[SP].playernum].name;
}
@ -2123,7 +2123,7 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr)
// no team messages in teamplay 0, except for our own
if (cl.spectator)
{
unsigned int track = Cam_TrackNum(0);
unsigned int track = Cam_TrackNum(&cl.playerview[SP]);
if (i == track || ( cl.teamplay &&
!strcmp(cl.players[track].team, player->team)) )
{
@ -2132,8 +2132,8 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr)
}
else
{
if (i == cl.playernum[SP] || ( cl.teamplay &&
!strcmp(cl.players[cl.playernum[SP]].team, player->team)) )
if (i == cl.playerview[SP].playernum || ( cl.teamplay &&
!strcmp(cl.players[cl.playerview[SP].playernum].team, player->team)) )
{
flags |= TPM_TEAM;
}
@ -2511,7 +2511,7 @@ static int FindNearestItem (int flags, item_t **pitem)
item_t *item;
VectorCopy (cl.inframes[cl.validsequence&UPDATE_MASK]
.playerstate[cl.playernum[SP]].origin, org);
.playerstate[cl.playerview[SP].playernum].origin, org);
// look in previous frame
frame = &cl.inframes[cl.oldvalidsequence&UPDATE_MASK];
@ -2561,9 +2561,9 @@ static int CountTeammates (void)
return 0;
count = 0;
myteam = cl.players[cl.playernum[SP]].team;
myteam = cl.players[cl.playerview[SP].playernum].team;
for (i=0, player=cl.players; i < MAX_CLIENTS ; i++, player++) {
if (player->name[0] && !player->spectator && (i != cl.playernum[SP])
if (player->name[0] && !player->spectator && (i != cl.playerview[SP].playernum)
&& !strcmp(player->team, myteam))
count++;
}
@ -2587,9 +2587,9 @@ static qboolean CheckTrigger (void)
return false;
count = 0;
myteam = cl.players[cl.playernum[0]].team;
myteam = cl.players[cl.playerview[SP].playernum].team;
for (i = 0, player= cl.players; i < MAX_CLIENTS; i++, player++) {
if (player->name[0] && !player->spectator && i != cl.playernum[0] && !strcmp(player->team, myteam))
if (player->name[0] && !player->spectator && i != cl.playerview[SP].playernum && !strcmp(player->team, myteam))
count++;
}
@ -2647,11 +2647,11 @@ void TP_ParsePlayerInfo(player_state_t *oldstate, player_state_t *state, player_
vars.enemy_powerups |= TP_RING;
}
}
if (!cl.spectator && !cl.teamfortress && info - cl.players == cl.playernum[SP])
if (!cl.spectator && !cl.teamfortress && info - cl.players == cl.playerview[SP].playernum)
{
if ((state->effects & (QWEF_FLAG1|QWEF_FLAG2)) && !(oldstate->effects & (QWEF_FLAG1|QWEF_FLAG2)))
{
ExecTookTrigger (tp_name_flag.string, it_flag, cl.inframes[cl.validsequence & UPDATE_MASK].playerstate[cl.playernum[SP]].origin);
ExecTookTrigger (tp_name_flag.string, it_flag, cl.inframes[cl.validsequence & UPDATE_MASK].playerstate[cl.playerview[SP].playernum].origin);
}
else if (!(state->effects & (QWEF_FLAG1|QWEF_FLAG2)) && (oldstate->effects & (QWEF_FLAG1|QWEF_FLAG2)))
{
@ -2976,7 +2976,7 @@ static void TP_FindPoint (void)
info = cl.players;
for (j = 0; j < MAX_CLIENTS; j++, info++, state++)
{
if (state->messagenum != cl.parsecount || j == cl.playernum[0] || info->spectator)
if (state->messagenum != cl.parsecount || j == cl.playerview[SP].playernum || info->spectator)
continue;
if (
@ -3177,7 +3177,7 @@ void TP_StatChanged (int stat, int value)
if (cl.teamfortress && !cl.spectator)
{
ExecTookTrigger (tp_name_flag.string, it_flag,
cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[cl.playernum[SP]].origin);
cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[cl.playerview[SP].playernum].origin);
}
}
@ -3420,7 +3420,7 @@ qboolean TP_SuppressMessage(char *buf) {
*s++ = '\n';
*s++ = 0;
return (!cls.demoplayback && !cl.spectator && *s - 'A' == cl.playernum[0]);
return (!cls.demoplayback && !cl.spectator && *s - 'A' == cl.playerview[SP].playernum);
}
return false;
}
@ -3505,7 +3505,7 @@ void CL_Say (qboolean team, char *extra)
if (team)
plrflags |= 2;
CL_PrintChat(&cl.players[cl.playernum[SP]], NULL, text, plrflags);
CL_PrintChat(&cl.players[cl.playerview[SP].playernum], NULL, text, plrflags);
}
//strip out the extra markup
@ -3533,7 +3533,7 @@ void CL_Say (qboolean team, char *extra)
*d = '\0';
//mark the message so that we ignore it when we get the echo.
strlcat (sendtext, va("\x7f!%c", 'A'+cl.playernum[0]), sizeof(sendtext));
strlcat (sendtext, va("\x7f!%c", 'A'+cl.playerview[SP].playernum), sizeof(sendtext));
}
#ifdef Q3CLIENT

View File

@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// release version
#define FTE_VER_MAJOR 1
#define FTE_VER_MINOR 2
#define FTE_VER_MINOR 3
//#define VERSION 2.56
#ifndef DISTRIBUTION
@ -240,10 +240,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define TCPCONNECT //a tcpconnect command, that allows the player to connect to tcp-encapsulated qw protocols.
#define IRCCONNECT //an ircconnect command, that allows the player to connect to irc-encapsulated qw protocols... yeah, really.
#define PLUGINS
#define PLUGINS //qvm/dll plugins.
#define SUPPORT_ICE //Internet Connection Establishment protocol, for peer-to-peer connections
#ifdef _DEBUG
// #define OFFSCREENGECKO
// #define OFFSCREENGECKO //FIXME: move to plugin and remove from engine
#endif
#define CSQC_DAT //support for csqc

View File

@ -25,24 +25,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_MAP_HULLSDH2 8
#define MAX_MAP_HULLSM 16
#define MAX_MAP_MODELS 256
#define MAX_MAP_BRUSHES 0x8000
#define MAX_MAP_ENTITIES 1024
#define MAX_MAP_ENTSTRING 65536
//#define MAX_MAP_MODELS 256
//#define MAX_MAP_BRUSHES 0x8000
//#define MAX_MAP_ENTITIES 1024
//#define MAX_MAP_ENTSTRING 65536
#define MAX_MAP_PLANES 65636*2
#define MAX_MAP_NODES 65535 // q2/q3 uses more than q1. :(
#define MAX_MAP_CLIPNODES 65535 //
#define MAX_MAP_LEAFS 65535 //
#define MAX_MAP_VERTS 65535
#define MAX_MAP_FACES 65535
#define MAX_MAP_MARKSURFACES 65535
#define MAX_MAP_TEXINFO 4096
#define MAX_MAP_PLANES 65636*2 //sanity (used by q2)
#define SANITY_MAX_MAP_NODES 65535 //sanity
#define SANITY_MAX_MAP_CLIPNODES 65535 //sanity
#define MAX_MAP_LEAFS 65535 //pvs buffer size. not sanity.
#define SANITY_MAX_MAP_VERTS 65535 //sanity
#define SANITY_MAX_MAP_FACES 65535 //sanity
//#define MAX_MAP_MARKSURFACES 65535 //sanity
//#define MAX_MAP_TEXINFO 4096 //sanity
#define MAX_MAP_EDGES 256000
#define MAX_MAP_SURFEDGES 512000
#define MAX_MAP_MIPTEX 0x200000
#define MAX_MAP_LIGHTING 0x100000
#define MAX_MAP_VISIBILITY 0x200000
//#define MAX_MAP_SURFEDGES 512000
//#define MAX_MAP_MIPTEX 0x200000
//#define MAX_MAP_LIGHTING 0x100000
//#define MAX_MAP_VISIBILITY 0x200000
// key / value pair sizes
@ -406,8 +406,8 @@ typedef struct q2miptex_s
// leaffaces, leafbrushes, planes, and verts are still bounded by
// 16 bit short limits
#define MAX_Q2MAP_MODELS 1024
#define MAX_Q2MAP_BRUSHES MAX_MAP_BRUSHES
#define MAX_Q2MAP_ENTITIES 2048
#define SANITY_MAX_MAP_BRUSHES 0x8000
#define MAX_Q2MAP_AREAS 256
#define MAX_Q2MAP_AREAPORTALS 1024
@ -415,12 +415,12 @@ typedef struct q2miptex_s
#define MAX_Q2MAP_BRUSHSIDES 0x40000
#define MAX_Q2MAP_VERTS MAX_MAP_VERTS
#define MAX_Q2MAP_FACES MAX_MAP_FACES
#define MAX_Q2MAP_LEAFFACES 262144 //sanity only
#define SANITY_MAX_MAP_LEAFFACES 262144 //sanity only
#define MAX_Q2MAP_LEAFBRUSHES 65536 //used in an array
#define MAX_Q2MAP_PORTALS 65536 //unused
#define MAX_Q2MAP_EDGES 128000 //unused
#define MAX_Q2MAP_SURFEDGES 256000 //unused
#define MAX_Q2MAP_LIGHTING 0x200000 //unused
//#define MAX_Q2MAP_PORTALS 65536 //unused
//#define MAX_Q2MAP_EDGES 128000 //unused
//#define MAX_Q2MAP_SURFEDGES 256000 //unused
//#define MAX_Q2MAP_LIGHTING 0x200000 //unused
//#define MAX_Q2MAP_VISIBILITY MAX_MAP_VISIBILITY
// key / value pair sizes

View File

@ -45,7 +45,7 @@ typedef struct cmdalias_s
cmdalias_t *cmd_alias;
cvar_t cl_warncmd = SCVAR("cl_warncmd", "0");
cvar_t cl_warncmd = SCVAR("cl_warncmd", "1");
cvar_t cl_aliasoverlap = SCVARF("cl_aliasoverlap", "1", CVAR_NOTFROMSERVER);
cvar_t tp_disputablemacros = SCVARF("tp_disputablemacros", "1", CVAR_SEMICHEAT);
@ -537,8 +537,8 @@ void Cmd_Exec_f (void)
Con_DPrintf("Ignoring UTF-8 BOM\n");
s+=3;
}
// don't execute anything as if it was from server
Cbuf_InsertText (s, Cmd_FromGamecode() ? RESTRICT_INSECURE : Cmd_ExecLevel, true);
// don't execute anything if it was from server (either the stuffcmd/localcmd, or the file)
Cbuf_InsertText (s, ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), true);
FS_FreeFile(f);
}
@ -1881,14 +1881,15 @@ void Cmd_ForwardToServer_f (void)
}
if (Q_strcasecmp(Cmd_Argv(1), "ptrack") == 0)
{
playerview_t *pv = &cl.playerview[CL_TargettedSplit(false)];
if (!*Cmd_Argv(2))
{
Cam_Unlock(0);
Cam_Unlock(pv);
}
else
{
Cam_Lock(0, atoi(Cmd_Argv(2)));
autocam[0] = CAM_TRACK;
Cam_Lock(pv, atoi(Cmd_Argv(2)));
pv->cam_auto = CAM_TRACK;
}
return;
}
@ -3070,6 +3071,7 @@ void Cmd_Init (void)
Cvar_Register(&tp_disputablemacros, "Teamplay");
Cvar_Register(&dpcompat_set, "Darkplaces compatibility");
Cvar_Register (&cl_warncmd, "Warnings");
#ifndef SERVERONLY
rcon_level.ival = atof(rcon_level.defaultstr); //client is restricted to not be allowed to change restrictions.

View File

@ -123,10 +123,13 @@ void Cmd_ExecuteString (char *text, int restrictionlevel);
void Cmd_Args_Set(char *newargs);
#define RESTRICT_MAX 29 //1-64 it's all about bit size. This is max settable. servers are +1 or +2
#define RESTRICT_MAX_TOTAL 31
#define RESTRICT_MAX_USER 29 //1-64 it's all about bit size. This is max settable. servers are +1 or +2
#define RESTRICT_DEFAULT 20 //rcon get's 63, local always gets 64
#define RESTRICT_MIN 1 //rcon get's 63, local always gets 64
#define RESTRICT_MAX RESTRICT_MAX_USER
#define RESTRICT_LOCAL RESTRICT_MAX
#define RESTRICT_INSECURE RESTRICT_MAX+1
#define RESTRICT_SERVER RESTRICT_MAX+2

View File

@ -2023,6 +2023,10 @@ void Mod_BuildTextureVectors(galiasinfo_t *galias)
int vbospace = 0;
vbobctx_t vboctx;
//don't fail on dedicated servers
if (!BE_VBO_Begin)
return;
idx = (index_t*)((char*)galias + galias->ofs_indexes);
tc = (vec2_t*)((char*)galias + galias->ofs_st_array);
group = (galiasgroup_t*)((char*)galias + galias->groupofs);
@ -3600,7 +3604,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
float f2ness;
#ifdef warningmsg
#pragma warningmsg("fixme: no base info")
#pragma warningmsg("fixme: no baseframe info")
#endif
if (tagnum <= 0 || tagnum > inf->numbones)

View File

@ -9,61 +9,6 @@
int HLMod_BoneForName(model_t *mod, char *name);
int HLMod_FrameForName(model_t *mod, char *name);
typedef struct {
int ofs_indexes;
int numindexes;
int ofs_trineighbours;
int numskins;
#ifndef SERVERONLY
int ofsskins;
#endif
int shares_verts; //used with models with two shaders using the same vertex. set to the surface number to inherit from (or itself).
int shares_bones; //use last mesh's bones. set to the surface number to inherit from (or itself).
int numverts;
#ifndef SERVERONLY
int ofs_st_array;
#endif
int groups;
int groupofs;
int baseframeofs; /*non-heirachical*/
int nextsurf;
#ifdef SKELETALMODELS
int numbones;
int ofsbones;
int numswtransforms;
int ofsswtransforms;
int ofs_skel_xyz;
int ofs_skel_norm;
int ofs_skel_svect;
int ofs_skel_tvect;
int ofs_skel_idx;
int ofs_skel_weight;
vboarray_t vbo_skel_verts;
vboarray_t vbo_skel_normals;
vboarray_t vbo_skel_svector;
vboarray_t vbo_skel_tvector;
vboarray_t vbo_skel_bonenum;
vboarray_t vbo_skel_bweight;
#endif
vboarray_t vboindicies;
vboarray_t vbotexcoords;
//these exist only in the root mesh.
int numtagframes;
int numtags;
int ofstags;
} galiasinfo_t;
//frame is an index into this
typedef struct
{
@ -142,6 +87,62 @@ typedef struct {
} galiascolourmapped_t;
#endif
typedef struct {
int ofs_indexes;
int numindexes;
int ofs_trineighbours;
int numskins;
#ifndef SERVERONLY
int ofsskins;
#endif
int shares_verts; //used with models with two shaders using the same vertex. set to the surface number to inherit from (or itself).
int shares_bones; //use last mesh's bones. set to the surface number to inherit from (or itself).
int numverts;
#ifndef SERVERONLY
int ofs_st_array;
#endif
int groups;
int groupofs;
int baseframeofs; /*non-heirachical*/
int nextsurf;
#ifdef SKELETALMODELS
int numbones;
int ofsbones;
int numswtransforms;
int ofsswtransforms;
int ofs_skel_xyz;
int ofs_skel_norm;
int ofs_skel_svect;
int ofs_skel_tvect;
int ofs_skel_idx;
int ofs_skel_weight;
vboarray_t vbo_skel_verts;
vboarray_t vbo_skel_normals;
vboarray_t vbo_skel_svector;
vboarray_t vbo_skel_tvector;
vboarray_t vbo_skel_bonenum;
vboarray_t vbo_skel_bweight;
#endif
vboarray_t vboindicies;
vboarray_t vbotexcoords;
//these exist only in the root mesh.
int numtagframes;
int numtags;
int ofstags;
} galiasinfo_t;
float *Alias_GetBonePositions(galiasinfo_t *inf, framestate_t *fstate, float *buffer, int buffersize, qboolean renderable);
#ifdef SKELETALMODELS
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout);

View File

@ -94,7 +94,7 @@ cvar_t gameversion = CVARFD("gameversion","", CVAR_SERVERINFO, "gamecode version
cvar_t gameversion_min = CVARD("gameversion_min","", "gamecode version for server browsers");
cvar_t gameversion_max = CVARD("gameversion_max","", "gamecode version for server browsers");
cvar_t fs_gamename = CVARFD("fs_gamename", "", CVAR_NOSET, "The filesystem is trying to run this game");
cvar_t fs_gamedownload = CVARFD("fs_gamedownload", "", CVAR_NOSET, "The place that the game can be downloaded from.");
cvar_t fs_gamemanifest = CVARFD("fs_gamemanifest", "", CVAR_NOSET, "A small updatable file containing a description of the game, including download mirrors.");
cvar_t com_protocolname = CVARD("com_gamename", "", "The game name used for dpmaster queries");
cvar_t com_modname = CVARD("com_modname", "", "dpmaster information");
cvar_t com_parseutf8 = CVARD("com_parseutf8", "0", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed.
@ -2306,7 +2306,7 @@ unsigned int unicode_byteofsfromcharofs(char *str, unsigned int charofs)
{
char *in = str;
int error;
int chars = 0;
int chars;
for(chars = 0; *in; chars+=1)
{
if (chars >= charofs)
@ -2314,7 +2314,7 @@ unsigned int unicode_byteofsfromcharofs(char *str, unsigned int charofs)
unicode_decode(&error, in, &in);
}
return chars;
return in - str;
}
//handy hacky function.
unsigned int unicode_charofsfrombyteofs(char *str, unsigned int byteofs)
@ -2568,6 +2568,43 @@ char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, q
return out;
}
static unsigned int koi2wc (unsigned char uc)
{
static const char koi2wc_table[64] =
{
0x4e,0x30,0x31,0x46,0x34,0x35,0x44,0x33,0x45,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,
0x3f,0x4f,0x40,0x41,0x42,0x43,0x36,0x32,0x4c,0x4b,0x37,0x48,0x4d,0x49,0x47,0x4a,
0x2e,0x10,0x11,0x26,0x14,0x15,0x24,0x13,0x25,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,
0x1f,0x2f,0x20,0x21,0x22,0x23,0x16,0x12,0x2c,0x2b,0x17,0x28,0x2d,0x29,0x27,0x2a
};
if (uc >= 192 /* && (unsigned char)c <= 255 */)
return koi2wc_table[uc - 192] + 0x400;
else if (uc == '#' + 128)
return 0x0451; // russian small yo
else if (uc == '3' + 128)
return 0x0401; // russian capital yo
else if (uc == '4' + 128)
return 0x0404; // ukrainian capital round E
else if (uc == '$' + 128)
return 0x0454; // ukrainian small round E
else if (uc == '6' + 128)
return 0x0406; // ukrainian capital I
else if (uc == '&' + 128)
return 0x0456; // ukrainian small i
else if (uc == '7' + 128)
return 0x0407; // ukrainian capital I with two dots
else if (uc == '\'' + 128)
return 0x0457; // ukrainian small i with two dots
else if (uc == '>' + 128)
return 0x040e; // belarusian Y
else if (uc == '.' + 128)
return 0x045e; // belarusian y
else if (uc == '/' + 128)
return 0x042a; // russian capital hard sign
else
return uc;
}
//Takes a q3-style fun string, and returns an expanded string-with-flags (actual return value is the null terminator)
//outsize parameter is in _BYTES_ (so sizeof is safe).
conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int flags)
@ -2837,6 +2874,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
}
else if (*str == '&' && str[1] == 'r' && !(flags & PFS_NOMARKUP))
{
//ezquake revert
ext = (COLOR_WHITE << CON_FGSHIFT) | (ext&~(CON_RICHFOREMASK|CON_RICHFORECOLOUR));
if (!keepmarkup)
{
@ -2844,6 +2882,30 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
continue;
}
}
else if (str[0] == '=' && str[1] == '`' && str[2] == 'k' && str[3] == '8' && str[4] == ':' && !keepmarkup)
{
//this code can just recurse. saves affecting the rest of the code with weird encodings.
int l;
char temp[1024];
str += 5;
while(*str)
{
l = 0;
while (*str && l < sizeof(temp)-32 && !(str[0] == '`' && str[1] == '='))
l += utf8_encode(temp+l, koi2wc(*str++), sizeof(temp)-1);
//recurse
temp[l] = 0;
l = COM_ParseFunString(ext, temp, out, outsize, PFS_FORCEUTF8) - out;
outsize -= l;
out += l;
if (str[0] == '`' && str[1] == '=')
{
str+=2;
break;
}
}
continue;
}
messedup:
if (!--outsize)
break;
@ -4598,7 +4660,7 @@ void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsi
Info_SetValueForStarKey (s, key, value, maxsize);
}
void Info_Print (char *s)
void Info_Print (char *s, char *lineprefix)
{
char key[1024];
char value[1024];
@ -4621,7 +4683,7 @@ void Info_Print (char *s)
}
else
*o = 0;
Con_Printf ("%s", key);
Con_Printf ("%s%s", lineprefix, key);
if (!*s)
{

View File

@ -326,6 +326,7 @@ char *VARGS va(char *format, ...) LIKEPRINTF(1);
extern qboolean com_file_copyprotected;
extern int com_filesize;
extern qboolean com_file_untrusted;
struct cache_user_s;
extern char com_quakedir[MAX_OSPATH];
@ -355,7 +356,7 @@ char *FS_WhichPackForLocation(flocation_t *loc);
qboolean FS_GetPackageDownloadable(const char *package);
char *FS_GetPackHashes(char *buffer, int buffersize, qboolean referencedonly);
char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean ext);
void FS_GenCachedPakName(char *pname, char *crc, char *local, int llen);
qboolean FS_GenCachedPakName(char *pname, char *crc, char *local, int llen); //returns false if the name is invalid.
void FS_ReferenceControl(unsigned int refflag, unsigned int resetflags);
FTE_DEPRECATED int COM_FOpenFile (const char *filename, FILE **file);
@ -386,6 +387,7 @@ typedef struct vfsfile_s
char dbgname[MAX_QPATH];
#endif
} vfsfile_t;
typedef struct searchpathfuncs_s searchpathfuncs_t;
#define VFS_CLOSE(vf) (vf->Close(vf))
#define VFS_TELL(vf) (vf->Tell(vf))
@ -421,9 +423,11 @@ qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_
vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto);
vfsfile_t *FS_OpenTemp(void);
vfsfile_t *FS_OpenTCP(const char *name, int defaultport);
void FS_UnloadPackFiles(void);
void FS_ReloadPackFiles(void);
char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum);
void FS_PureMode(int mode, char *packagelist, char *crclist, int seed); //implies an fs_restart
qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize);
@ -432,15 +436,37 @@ qbyte *COM_LoadTempMoreFile (const char *path); //allocates a little bit more wi
qbyte *COM_LoadHunkFile (const char *path);
qbyte *COM_LoadMallocFile (const char *path);
void COM_LoadCacheFile (const char *path, struct cache_user_s *cu);
void FS_ForceToPure(const char *str, const char *crcs, int seed);
void FS_ImpurePacks(const char *names, const char *crcs);
char *COM_GetPathInfo (int i, int *crc);
char *COM_NextPath (char *prevpath);
searchpathfuncs_t *COM_IteratePaths (void **iterator, char *buffer, int buffersize);
void COM_FlushFSCache(void); //a file was written using fopen
void COM_RefreshFSCache_f(void);
qboolean FS_Restarted(unsigned int *since);
void COM_InitFilesystem (void);
typedef struct
{
char *updateurl; //url to download an updated manifest file from.
char *installation; //optional hardcoded commercial name, used for scanning the registry to find existing installs.
char *formalname; //the commercial name of the game. you'll get FULLENGINENAME otherwise.
char *protocolname; //the name used for purposes of dpmaster
char *defaultexec; //execed after cvars are reset, to give game-specific defaults.
struct
{
qboolean base;
char *path;
} gamepath[8];
struct
{
char *path; //the 'pure' name
unsigned int crc; //the public crc
char *mirrors[8]; //a randomized (prioritized) list of http mirrors to use.
int mirrornum; //the index we last tried to download from, so we still work even if mirrors are down.
} package[64];
} ftemanifest_t;
void FS_Manifest_Free(ftemanifest_t *man);
ftemanifest_t *FS_Manifest_Parse(const char *data);
void COM_InitFilesystem (void); //does not set up any gamedirs.
qboolean FS_ChangeGame(ftemanifest_t *newgame, qboolean allowreloadconfigs);
void FS_Shutdown(void);
void COM_Gamedir (const char *dir);
char *FS_GetGamedir(void);
@ -455,7 +481,7 @@ qbyte *COM_LoadFile (const char *path, int usehunk);
qboolean COM_LoadMapPackFile(const char *name, int offset);
void COM_FlushTempoaryPacks(void);
void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, void *spath), void *parm);
void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, searchpathfuncs_t *spath), void *parm);
extern struct cvar_s registered;
extern qboolean standard_quake; //fixme: remove
@ -474,7 +500,7 @@ void Info_RemovePrefixedKeys (char *start, char prefix);
void Info_RemoveNonStarKeys (char *start);
void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsize);
void Info_SetValueForStarKey (char *s, const char *key, const char *value, int maxsize);
void Info_Print (char *s);
void Info_Print (char *s, char *lineprefix);
void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags);
void Com_BlocksChecksum (int blocks, void **buffer, int *len, unsigned char *outbuf);

View File

@ -88,6 +88,7 @@ extern conchar_t q3codemasks[MAXQ3COLOURS];
#define S_COLOR_MAGENTA "^6"
#define S_COLOR_WHITE "^7"
#define CON_DEFAULT "^&--"
#define CON_WARNING "^&E0"
#define CON_ERROR "^&C0"
#define CON_NOTICE "^&-1"

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,7 @@
#include "hash.h"
#define FSVER 1
typedef struct
{
bucket_t buck;
@ -9,31 +12,43 @@ extern int fs_hash_dups; //for tracking efficiency. no functional use.
extern int fs_hash_files; //for tracking efficiency. no functional use.
struct searchpath_s;
typedef struct {
void (QDECL *GetDisplayPath)(void *handle, char *outpath, unsigned int pathsize);
void (QDECL *ClosePath)(void *handle);
void (QDECL *BuildHash)(void *handle, int depth, void (QDECL *FS_AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle));
qboolean (QDECL *FindFile)(void *handle, flocation_t *loc, const char *name, void *hashedresult); //true if found (hashedresult can be NULL)
struct searchpathfuncs_s
{
int fsver;
void (QDECL *ClosePath)(searchpathfuncs_t *handle);
void (QDECL *GetPathDetails)(searchpathfuncs_t *handle, char *outdetails, unsigned int sizeofdetails);
void (QDECL *BuildHash)(searchpathfuncs_t *handle, int depth, void (QDECL *FS_AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle));
qboolean (QDECL *FindFile)(searchpathfuncs_t *handle, flocation_t *loc, const char *name, void *hashedresult); //true if found (hashedresult can be NULL)
//note that if rawfile and offset are set, many Com_FileOpens will read the raw file
//otherwise ReadFile will be called instead.
void (QDECL *ReadFile)(void *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives)
int (QDECL *EnumerateFiles)(void *handle, const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, void *spath), void *parm);
void (QDECL *ReadFile)(searchpathfuncs_t *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives)
int (QDECL *EnumerateFiles)(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, searchpathfuncs_t *spath), void *parm);
void *(QDECL *OpenNew)(vfsfile_t *file, const char *desc); //returns a handle to a new pak/path
int (QDECL *GeneratePureCRC) (searchpathfuncs_t *handle, int seed, int usepure);
int (QDECL *GeneratePureCRC) (void *handle, int seed, int usepure);
vfsfile_t *(QDECL *OpenVFS)(searchpathfuncs_t *handle, flocation_t *loc, const char *mode);
vfsfile_t *(QDECL *OpenVFS)(void *handle, flocation_t *loc, const char *mode);
qboolean (QDECL *PollChanges)(void *handle); //returns true if there were changes
} searchpathfuncs_t;
qboolean (QDECL *PollChanges)(searchpathfuncs_t *handle); //returns true if there were changes
};
//searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc); //returns a handle to a new pak/path
//the stdio filesystem is special as that's the starting point of the entire filesystem
//warning: the handle is known to be a string pointer to the dir name
extern searchpathfuncs_t osfilefuncs;
extern searchpathfuncs_t *(QDECL VFSOS_OpenPath) (vfsfile_t *file, const char *desc);
extern searchpathfuncs_t *(QDECL FSZIP_LoadArchive) (vfsfile_t *packhandle, const char *desc);
extern searchpathfuncs_t *(QDECL FSPAK_LoadArchive) (vfsfile_t *packhandle, const char *desc);
extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *packhandle, const char *desc);
vfsfile_t *QDECL VFSOS_Open(const char *osname, const char *mode);
vfsfile_t *FS_DecompressGZip(vfsfile_t *infile);
vfsfile_t *FS_DecompressGZip(vfsfile_t *infile, vfsfile_t *outfile);
int FS_RegisterFileSystemType(void *module, const char *extension, searchpathfuncs_t *funcs, qboolean loadscan);
int FS_RegisterFileSystemType(void *module, const char *extension, searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc), qboolean loadscan);
void FS_UnRegisterFileSystemType(int idx);
void FS_UnRegisterFileSystemModule(void *module);
#define SPF_REFERENCED 1 //something has been loaded from this path. should filter out client references...
#define SPF_COPYPROTECTED 2 //downloads are not allowed fom here.
#define SPF_TEMPORARY 4 //a map-specific path, purged at map change.
#define SPF_EXPLICIT 8 //a root gamedir (bumps depth on gamedir depth checks).
#define SPF_UNTRUSTED 16 //has been downloaded from somewhere. configs inside it should never be execed with local access rights.
qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags);

View File

@ -15,6 +15,7 @@ typedef struct
typedef struct pack_s
{
searchpathfuncs_t pub;
char descname[MAX_OSPATH];
vfsfile_t *handle;
unsigned int filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek)
@ -54,16 +55,15 @@ typedef struct
#define MAX_FILES_IN_PACK 2048
void QDECL FSPAK_GetDisplayPath(void *handle, char *out, unsigned int outlen)
static void QDECL FSPAK_GetPathDetails(searchpathfuncs_t *handle, char *out, unsigned int outlen)
{
pack_t *pak = handle;
pack_t *pak = (pack_t*)handle;
*out = 0;
if (pak->references != 1)
Q_snprintfz(out, outlen, "%s (%i)", pak->descname, pak->references-1);
else
Q_snprintfz(out, outlen, "%s", pak->descname);
Q_snprintfz(out, outlen, "(%i)", pak->references-1);
}
void QDECL FSPAK_ClosePath(void *handle)
static void QDECL FSPAK_ClosePath(void *handle)
{
pack_t *pak = handle;
@ -125,9 +125,9 @@ qboolean QDECL FSPAK_FLocate(void *handle, flocation_t *loc, const char *filenam
}
return false;
}
int QDECL FSPAK_EnumerateFiles (void *handle, const char *match, int (QDECL *func)(const char *, int, void *, void *spath), void *parm)
static int QDECL FSPAK_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t *spath), void *parm)
{
pack_t *pak = handle;
pack_t *pak = (pack_t*)handle;
int num;
for (num = 0; num<(int)pak->numfiles; num++)
@ -171,102 +171,6 @@ int QDECL FSPAK_GeneratePureCRC(void *handle, int seed, int crctype)
return result;
}
/*
=================
COM_LoadPackFile
Takes an explicit (not game tree related) path to a pak file.
Loads the header and directory, adding the files at the beginning
of the list so they override previous pack files.
=================
*/
void *QDECL FSPAK_LoadPackFile (vfsfile_t *file, const char *desc)
{
dpackheader_t header;
int i;
// int j;
mpackfile_t *newfiles;
int numpackfiles;
pack_t *pack;
vfsfile_t *packhandle;
dpackfile_t info;
int read;
// unsigned short crc;
packhandle = file;
if (packhandle == NULL)
return NULL;
read = VFS_READ(packhandle, &header, sizeof(header));
if (read < sizeof(header) || header.id[0] != 'P' || header.id[1] != 'A'
|| header.id[2] != 'C' || header.id[3] != 'K')
{
Con_Printf("%s is not a pak - %c%c%c%c\n", desc, header.id[0], header.id[1], header.id[2], header.id[3]);
return NULL;
}
header.dirofs = LittleLong (header.dirofs);
header.dirlen = LittleLong (header.dirlen);
numpackfiles = header.dirlen / sizeof(dpackfile_t);
// if (numpackfiles > MAX_FILES_IN_PACK)
// Sys_Error ("%s has %i files", packfile, numpackfiles);
// if (numpackfiles != PAK0_COUNT)
// com_modified = true; // not the original file
newfiles = (mpackfile_t*)Z_Malloc (numpackfiles * sizeof(mpackfile_t));
VFS_SEEK(packhandle, header.dirofs);
// fread (&info, 1, header.dirlen, packhandle);
// crc the directory to check for modifications
// crc = QCRC_Block((qbyte *)info, header.dirlen);
// QCRC_Init (&crc);
pack = (pack_t*)Z_Malloc (sizeof (pack_t));
// parse the directory
for (i=0 ; i<numpackfiles ; i++)
{
*info.name = '\0';
read = VFS_READ(packhandle, &info, sizeof(info));
if (read != sizeof(info))
{
Con_Printf("PAK file table truncated, only found %i files out of %i\n", i, numpackfiles);
numpackfiles = i;
break;
}
/*
for (j=0 ; j<sizeof(info) ; j++)
CRC_ProcessByte(&crc, ((qbyte *)&info)[j]);
*/
strcpy (newfiles[i].name, info.name);
newfiles[i].name[MAX_QPATH-1] = 0; //paranoid
COM_CleanUpPath(newfiles[i].name); //blooming tanks.
newfiles[i].filepos = LittleLong(info.filepos);
newfiles[i].filelen = LittleLong(info.filelen);
}
/*
if (crc != PAK0_CRC)
com_modified = true;
*/
strcpy (pack->descname, desc);
pack->handle = packhandle;
pack->numfiles = numpackfiles;
pack->files = newfiles;
pack->filepos = 0;
VFS_SEEK(packhandle, pack->filepos);
pack->references++;
Con_TPrintf (TL_ADDEDPACKFILE, desc, numpackfiles);
return pack;
}
typedef struct {
vfsfile_t funcs;
pack_t *parentpak;
@ -376,22 +280,114 @@ void QDECL FSPAK_ReadFile(void *handle, flocation_t *loc, char *buffer)
*/
}
searchpathfuncs_t packfilefuncs = {
FSPAK_GetDisplayPath,
FSPAK_ClosePath,
FSPAK_BuildHash,
FSPAK_FLocate,
FSPAK_ReadFile,
FSPAK_EnumerateFiles,
FSPAK_LoadPackFile,
FSPAK_GeneratePureCRC,
FSPAK_OpenVFS
};
/*
=================
COM_LoadPackFile
Takes an explicit (not game tree related) path to a pak file.
Loads the header and directory, adding the files at the beginning
of the list so they override previous pack files.
=================
*/
searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, const char *desc)
{
dpackheader_t header;
int i;
// int j;
mpackfile_t *newfiles;
int numpackfiles;
pack_t *pack;
vfsfile_t *packhandle;
dpackfile_t info;
int read;
// unsigned short crc;
packhandle = file;
if (packhandle == NULL)
return NULL;
read = VFS_READ(packhandle, &header, sizeof(header));
if (read < sizeof(header) || header.id[0] != 'P' || header.id[1] != 'A'
|| header.id[2] != 'C' || header.id[3] != 'K')
{
Con_Printf("%s is not a pak - %c%c%c%c\n", desc, header.id[0], header.id[1], header.id[2], header.id[3]);
return NULL;
}
header.dirofs = LittleLong (header.dirofs);
header.dirlen = LittleLong (header.dirlen);
numpackfiles = header.dirlen / sizeof(dpackfile_t);
// if (numpackfiles > MAX_FILES_IN_PACK)
// Sys_Error ("%s has %i files", packfile, numpackfiles);
// if (numpackfiles != PAK0_COUNT)
// com_modified = true; // not the original file
newfiles = (mpackfile_t*)Z_Malloc (numpackfiles * sizeof(mpackfile_t));
VFS_SEEK(packhandle, header.dirofs);
// fread (&info, 1, header.dirlen, packhandle);
// crc the directory to check for modifications
// crc = QCRC_Block((qbyte *)info, header.dirlen);
// QCRC_Init (&crc);
pack = (pack_t*)Z_Malloc (sizeof (pack_t));
// parse the directory
for (i=0 ; i<numpackfiles ; i++)
{
*info.name = '\0';
read = VFS_READ(packhandle, &info, sizeof(info));
if (read != sizeof(info))
{
Con_Printf("PAK file table truncated, only found %i files out of %i\n", i, numpackfiles);
numpackfiles = i;
break;
}
/*
for (j=0 ; j<sizeof(info) ; j++)
CRC_ProcessByte(&crc, ((qbyte *)&info)[j]);
*/
strcpy (newfiles[i].name, info.name);
newfiles[i].name[MAX_QPATH-1] = 0; //paranoid
COM_CleanUpPath(newfiles[i].name); //blooming tanks.
newfiles[i].filepos = LittleLong(info.filepos);
newfiles[i].filelen = LittleLong(info.filelen);
}
/*
if (crc != PAK0_CRC)
com_modified = true;
*/
strcpy (pack->descname, desc);
pack->handle = packhandle;
pack->numfiles = numpackfiles;
pack->files = newfiles;
pack->filepos = 0;
VFS_SEEK(packhandle, pack->filepos);
pack->references++;
Con_TPrintf (TL_ADDEDPACKFILE, desc, numpackfiles);
pack->pub.fsver = FSVER;
pack->pub.GetPathDetails = FSPAK_GetPathDetails;
pack->pub.ClosePath = FSPAK_ClosePath;
pack->pub.BuildHash = FSPAK_BuildHash;
pack->pub.FindFile = FSPAK_FLocate;
pack->pub.ReadFile = FSPAK_ReadFile;
pack->pub.EnumerateFiles = FSPAK_EnumerateFiles;
pack->pub.GeneratePureCRC = FSPAK_GeneratePureCRC;
pack->pub.OpenVFS = FSPAK_OpenVFS;
return &pack->pub;
}
#ifdef DOOMWADS
void *QDECL FSPAK_LoadDoomWadFile (vfsfile_t *packhandle, const char *desc)
searchpathfuncs_t *QDECL FSDWD_LoadArchive (vfsfile_t *packhandle, const char *desc)
{
dwadheader_t header;
int i;
@ -560,17 +556,16 @@ newsection:
pack->references++;
Con_TPrintf (TL_ADDEDPACKFILE, desc, numpackfiles);
return pack;
pack->pub.fsver = FSVER;
pack->pub.GetPathDetails = FSPAK_GetPathDetails;
pack->pub.ClosePath = FSPAK_ClosePath;
pack->pub.BuildHash = FSPAK_BuildHash;
pack->pub.FindFile = FSPAK_FLocate;
pack->pub.ReadFile = FSPAK_ReadFile;
pack->pub.EnumerateFiles = FSPAK_EnumerateFiles;
pack->pub.GeneratePureCRC = FSPAK_GeneratePureCRC;
pack->pub.OpenVFS = FSPAK_OpenVFS;
return &pack->pub;
}
searchpathfuncs_t doomwadfilefuncs = {
FSPAK_GetDisplayPath,
FSPAK_ClosePath,
FSPAK_BuildHash,
FSPAK_FLocate,
FSPAK_ReadFile,
FSPAK_EnumerateFiles,
FSPAK_LoadDoomWadFile,
NULL,
FSPAK_OpenVFS
};
#endif

View File

@ -9,12 +9,13 @@
#define Z_Malloc malloc
#else
#if !defined(_WIN32) || defined(_SDL)
#define stdiofilefuncs osfilefuncs
#define FSSTDIO_OpenPath VFSOS_OpenPath
#endif
#define FSSTDIO_OpenTemp FS_OpenTemp
#endif
typedef struct {
searchpathfuncs_t pub;
int depth;
void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle);
char rootpath[1];
@ -209,11 +210,6 @@ static vfsfile_t *QDECL FSSTDIO_OpenVFS(void *handle, flocation_t *loc, const ch
return f;
}
static void QDECL FSSTDIO_GetDisplayPath(void *handle, char *out, unsigned int outlen)
{
stdiopath_t *np = handle;
Q_strncpyz(out, np->rootpath, outlen);
}
static void QDECL FSSTDIO_ClosePath(void *handle)
{
Z_Free(handle);
@ -223,20 +219,6 @@ static qboolean QDECL FSSTDIO_PollChanges(void *handle)
// stdiopath_t *np = handle;
return true; //can't verify that or not, so we have to assume the worst
}
static void *QDECL FSSTDIO_OpenPath(vfsfile_t *mustbenull, const char *desc)
{
stdiopath_t *np;
int dlen = strlen(desc);
if (mustbenull)
return NULL;
np = Z_Malloc(sizeof(*np) + dlen);
if (np)
{
np->depth = 0;
memcpy(np->rootpath, desc, dlen+1);
}
return np;
}
static int QDECL FSSTDIO_RebuildFSHash(const char *filename, int filesize, void *data, void *spath)
{
stdiopath_t *sp = spath;
@ -325,24 +307,37 @@ static void QDECL FSSTDIO_ReadFile(void *handle, flocation_t *loc, char *buffer)
fclose(f);
}
static int QDECL FSSTDIO_EnumerateFiles (void *handle, const char *match, int (QDECL *func)(const char *, int, void *, void *spath), void *parm)
static int QDECL FSSTDIO_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t *spath), void *parm)
{
stdiopath_t *sp = handle;
stdiopath_t *sp = (stdiopath_t*)handle;
return Sys_EnumerateFiles(sp->rootpath, match, func, parm, handle);
}
searchpathfuncs_t stdiofilefuncs = {
FSSTDIO_GetDisplayPath,
FSSTDIO_ClosePath,
FSSTDIO_BuildHash,
FSSTDIO_FLocate,
FSSTDIO_ReadFile,
FSSTDIO_EnumerateFiles,
FSSTDIO_OpenPath,
NULL,
FSSTDIO_OpenVFS,
FSSTDIO_PollChanges
};
void *QDECL FSSTDIO_OpenPath(vfsfile_t *mustbenull, const char *desc)
{
stdiopath_t *np;
int dlen = strlen(desc);
if (mustbenull)
return NULL;
np = Z_Malloc(sizeof(*np) + dlen);
if (np)
{
np->depth = 0;
memcpy(np->rootpath, desc, dlen+1);
}
np->pub.fsver = FSVER;
np->pub.ClosePath = FSSTDIO_ClosePath;
np->pub.BuildHash = FSSTDIO_BuildHash;
np->pub.FindFile = FSSTDIO_FLocate;
np->pub.ReadFile = FSSTDIO_ReadFile;
np->pub.EnumerateFiles = FSSTDIO_EnumerateFiles;
np->pub.OpenVFS = FSSTDIO_OpenVFS;
np->pub.PollChanges = FSSTDIO_PollChanges;
return np;
}
#endif
#endif

View File

@ -10,10 +10,10 @@
//for write access, we use the stdio module as a fallback.
#define VFSW32_Open VFSOS_Open
#define w32filefuncs osfilefuncs
#define VFSW32_OpenPath VFSOS_OpenPath
typedef struct {
searchpathfuncs_t funcs;
searchpathfuncs_t pub;
HANDLE changenotification;
int hashdepth;
char rootpath[1];
@ -191,12 +191,6 @@ static vfsfile_t *QDECL VFSW32_OpenVFS(void *handle, flocation_t *loc, const cha
return VFSW32_Open(loc->rawname, mode);
}
static void QDECL VFSW32_GetDisplayPath(void *handle, char *out, unsigned int outlen)
{
vfsw32path_t *wp = handle;
Q_strncpyz(out, wp->rootpath, outlen);
}
static void QDECL VFSW32_ClosePath(void *handle)
{
vfsw32path_t *wp = handle;
@ -229,21 +223,6 @@ static qboolean QDECL VFSW32_PollChanges(void *handle)
}
return result;
}
static void *QDECL VFSW32_OpenPath(vfsfile_t *mustbenull, const char *desc)
{
vfsw32path_t *np;
int dlen = strlen(desc);
if (mustbenull)
return NULL;
np = Z_Malloc(sizeof(*np) + dlen);
if (np)
{
memcpy(np->rootpath, desc, dlen+1);
np->changenotification = FindFirstChangeNotification(np->rootpath, true, FILE_NOTIFY_CHANGE_FILE_NAME);
}
return np;
}
static int QDECL VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle, void *spath)
{
vfsw32path_t *wp = spath;
@ -317,22 +296,34 @@ static void QDECL VFSW32_ReadFile(void *handle, flocation_t *loc, char *buffer)
fread(buffer, 1, loc->len, f);
fclose(f);
}
static int QDECL VFSW32_EnumerateFiles (void *handle, const char *match, int (QDECL *func)(const char *, int, void *, void *spath), void *parm)
static int QDECL VFSW32_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t *spath), void *parm)
{
vfsw32path_t *wp = handle;
vfsw32path_t *wp = (vfsw32path_t*)handle;
return Sys_EnumerateFiles(wp->rootpath, match, func, parm, handle);
}
searchpathfuncs_t w32filefuncs = {
VFSW32_GetDisplayPath,
VFSW32_ClosePath,
VFSW32_BuildHash,
VFSW32_FLocate,
VFSW32_ReadFile,
VFSW32_EnumerateFiles,
VFSW32_OpenPath,
NULL,
VFSW32_OpenVFS,
VFSW32_PollChanges
};
searchpathfuncs_t *QDECL VFSW32_OpenPath(vfsfile_t *mustbenull, const char *desc)
{
vfsw32path_t *np;
int dlen = strlen(desc);
if (mustbenull)
return NULL;
np = Z_Malloc(sizeof(*np) + dlen);
if (np)
{
memcpy(np->rootpath, desc, dlen+1);
np->changenotification = FindFirstChangeNotification(np->rootpath, true, FILE_NOTIFY_CHANGE_FILE_NAME);
}
np->pub.fsver = FSVER;
np->pub.ClosePath = VFSW32_ClosePath;
np->pub.BuildHash = VFSW32_BuildHash;
np->pub.FindFile = VFSW32_FLocate;
np->pub.ReadFile = VFSW32_ReadFile;
np->pub.EnumerateFiles = VFSW32_EnumerateFiles;
np->pub.OpenVFS = VFSW32_OpenVFS;
np->pub.PollChanges = VFSW32_PollChanges;
return &np->pub;
}

View File

@ -71,7 +71,8 @@ qboolean LibZ_Init(void)
return ZLIB_LOADED();
}
vfsfile_t *FS_DecompressGZip(vfsfile_t *infile)
//outfile may be null
vfsfile_t *FS_DecompressGZip(vfsfile_t *infile, vfsfile_t *outfile)
{
char inchar;
unsigned short inshort;
@ -127,11 +128,16 @@ vfsfile_t *FS_DecompressGZip(vfsfile_t *infile)
temp = FS_OpenTemp();
if (!temp)
if (outfile)
temp = outfile;
else
{
VFS_SEEK(infile, 0); //doh
return infile;
temp = FS_OpenTemp();
if (!temp)
{
VFS_SEEK(infile, 0); //doh
return infile;
}
}
@ -222,6 +228,8 @@ typedef struct
typedef struct zipfile_s
{
searchpathfuncs_t pub;
char filename[MAX_OSPATH];
unzFile handle;
int numfiles;
@ -239,14 +247,14 @@ typedef struct zipfile_s
} zipfile_t;
static void QDECL FSZIP_GetDisplayPath(void *handle, char *out, unsigned int outlen)
static void QDECL FSZIP_GetPathDetails(void *handle, char *out, unsigned int outlen)
{
zipfile_t *zip = handle;
if (zip->references != 1)
Q_snprintfz(out, outlen, "%s (%i)\n", zip->filename, zip->references-1);
Q_snprintfz(out, outlen, "(%i)", zip->references-1);
else
Q_strncpyz(out, zip->filename, outlen);
*out = '\0';
}
static void QDECL FSZIP_ClosePath(void *handle)
{
@ -336,7 +344,7 @@ static void QDECL FSZIP_ReadFile(void *handle, flocation_t *loc, char *buffer)
return;
}
static int QDECL FSZIP_EnumerateFiles (void *handle, const char *match, int (QDECL *func)(const char *, int, void *, void *spath), void *parm)
static int QDECL FSZIP_EnumerateFiles (void *handle, const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t *spath), void *parm)
{
zipfile_t *zip = handle;
int num;
@ -345,7 +353,7 @@ static int QDECL FSZIP_EnumerateFiles (void *handle, const char *match, int (QDE
{
if (wildcmp(match, zip->files[num].name))
{
if (!func(zip->files[num].name, zip->files[num].filelen, parm, handle))
if (!func(zip->files[num].name, zip->files[num].filelen, parm, &zip->pub))
return false;
}
}
@ -353,68 +361,7 @@ static int QDECL FSZIP_EnumerateFiles (void *handle, const char *match, int (QDE
return true;
}
/*
=================
COM_LoadZipFile
Takes an explicit (not game tree related) path to a pak file.
Loads the header and directory, adding the files at the beginning
of the list so they override previous pack files.
=================
*/
static void *QDECL FSZIP_LoadZipFile (vfsfile_t *packhandle, const char *desc)
{
int i;
int nextfileziphandle;
zipfile_t *zip;
zpackfile_t *newfiles;
unz_global_info globalinf = {0};
unz_file_info file_info;
zip = Z_Malloc(sizeof(zipfile_t));
Q_strncpyz(zip->filename, desc, sizeof(zip->filename));
zip->handle = unzOpen ((zip->raw = packhandle));
if (!zip->handle)
{
Z_Free(zip);
Con_TPrintf (TL_COULDNTOPENZIP, desc);
return NULL;
}
unzGetGlobalInfo (zip->handle, &globalinf);
zip->numfiles = globalinf.number_entry;
zip->files = newfiles = Z_Malloc (zip->numfiles * sizeof(zpackfile_t));
for (i = 0; i < zip->numfiles; i++)
{
if (unzGetCurrentFileInfo (zip->handle, &file_info, newfiles[i].name, sizeof(newfiles[i].name), NULL, 0, NULL, 0) != UNZ_OK)
Con_Printf("Zip Error\n");
Q_strlwr(newfiles[i].name);
if (!*newfiles[i].name || newfiles[i].name[strlen(newfiles[i].name)-1] == '/')
newfiles[i].filelen = -1;
else
newfiles[i].filelen = file_info.uncompressed_size;
newfiles[i].filepos = file_info.c_offset;
nextfileziphandle = unzGoToNextFile (zip->handle);
if (nextfileziphandle == UNZ_END_OF_LIST_OF_FILE)
break;
else if (nextfileziphandle != UNZ_OK)
Con_Printf("Zip Error\n");
}
zip->references = 1;
zip->currentfile = NULL;
Con_TPrintf (TL_ADDEDZIPFILE, desc, zip->numfiles);
return zip;
}
int QDECL FSZIP_GeneratePureCRC(void *handle, int seed, int crctype)
static int QDECL FSZIP_GeneratePureCRC(void *handle, int seed, int crctype)
{
zipfile_t *zip = handle;
unz_file_info file_info;
@ -460,7 +407,7 @@ typedef struct {
int index;
int startpos;
} vfszip_t;
qboolean VFSZIP_MakeActive(vfszip_t *vfsz)
static qboolean VFSZIP_MakeActive(vfszip_t *vfsz)
{
int i;
char buffer[8192]; //must be power of two
@ -501,7 +448,7 @@ qboolean VFSZIP_MakeActive(vfszip_t *vfsz)
return true;
}
int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
static int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
{
int read;
vfszip_t *vfsz = (vfszip_t*)file;
@ -531,12 +478,12 @@ int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
vfsz->pos += read;
return read;
}
int QDECL VFSZIP_WriteBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
{
Sys_Error("VFSZIP_WriteBytes: Not supported\n");
return 0;
}
qboolean QDECL VFSZIP_Seek (struct vfsfile_s *file, unsigned long pos)
//static int QDECL VFSZIP_WriteBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
//{
// Sys_Error("VFSZIP_WriteBytes: Not supported\n");
// return 0;
//}
static qboolean QDECL VFSZIP_Seek (struct vfsfile_s *file, unsigned long pos)
{
vfszip_t *vfsz = (vfszip_t*)file;
@ -607,7 +554,7 @@ qboolean QDECL VFSZIP_Seek (struct vfsfile_s *file, unsigned long pos)
return true;
}
unsigned long QDECL VFSZIP_Tell (struct vfsfile_s *file)
static unsigned long QDECL VFSZIP_Tell (struct vfsfile_s *file)
{
vfszip_t *vfsz = (vfszip_t*)file;
@ -616,12 +563,12 @@ unsigned long QDECL VFSZIP_Tell (struct vfsfile_s *file)
return vfsz->pos;
}
unsigned long QDECL VFSZIP_GetLen (struct vfsfile_s *file)
static unsigned long QDECL VFSZIP_GetLen (struct vfsfile_s *file)
{
vfszip_t *vfsz = (vfszip_t*)file;
return vfsz->length;
}
void QDECL VFSZIP_Close (struct vfsfile_s *file)
static void QDECL VFSZIP_Close (struct vfsfile_s *file)
{
vfszip_t *vfsz = (vfszip_t*)file;
@ -635,7 +582,7 @@ void QDECL VFSZIP_Close (struct vfsfile_s *file)
Z_Free(vfsz);
}
vfsfile_t *QDECL FSZIP_OpenVFS(void *handle, flocation_t *loc, const char *mode)
static vfsfile_t *QDECL FSZIP_OpenVFS(void *handle, flocation_t *loc, const char *mode)
{
int rawofs;
zipfile_t *zip = handle;
@ -660,6 +607,7 @@ vfsfile_t *QDECL FSZIP_OpenVFS(void *handle, flocation_t *loc, const char *mode)
vfsz->funcs.Close = VFSZIP_Close;
vfsz->funcs.GetLen = VFSZIP_GetLen;
vfsz->funcs.ReadBytes = VFSZIP_ReadBytes;
//vfsz->funcs.WriteBytes = VFSZIP_WriteBytes;
vfsz->funcs.Seek = VFSZIP_Seek;
vfsz->funcs.Tell = VFSZIP_Tell;
vfsz->funcs.WriteBytes = NULL;
@ -694,17 +642,76 @@ vfsfile_t *QDECL FSZIP_OpenVFS(void *handle, flocation_t *loc, const char *mode)
return (vfsfile_t*)vfsz;
}
searchpathfuncs_t zipfilefuncs = {
FSZIP_GetDisplayPath,
FSZIP_ClosePath,
FSZIP_BuildHash,
FSZIP_FLocate,
FSZIP_ReadFile,
FSZIP_EnumerateFiles,
FSZIP_LoadZipFile,
FSZIP_GeneratePureCRC,
FSZIP_OpenVFS
};
/*
=================
COM_LoadZipFile
Takes an explicit (not game tree related) path to a pak file.
Loads the header and directory, adding the files at the beginning
of the list so they override previous pack files.
=================
*/
searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, const char *desc)
{
int i;
int nextfileziphandle;
zipfile_t *zip;
zpackfile_t *newfiles;
unz_global_info globalinf = {0};
unz_file_info file_info;
zip = Z_Malloc(sizeof(zipfile_t));
Q_strncpyz(zip->filename, desc, sizeof(zip->filename));
zip->handle = unzOpen ((zip->raw = packhandle));
if (!zip->handle)
{
Z_Free(zip);
Con_TPrintf (TL_COULDNTOPENZIP, desc);
return NULL;
}
unzGetGlobalInfo (zip->handle, &globalinf);
zip->numfiles = globalinf.number_entry;
zip->files = newfiles = Z_Malloc (zip->numfiles * sizeof(zpackfile_t));
for (i = 0; i < zip->numfiles; i++)
{
if (unzGetCurrentFileInfo (zip->handle, &file_info, newfiles[i].name, sizeof(newfiles[i].name), NULL, 0, NULL, 0) != UNZ_OK)
Con_Printf("Zip Error\n");
Q_strlwr(newfiles[i].name);
if (!*newfiles[i].name || newfiles[i].name[strlen(newfiles[i].name)-1] == '/')
newfiles[i].filelen = -1;
else
newfiles[i].filelen = file_info.uncompressed_size;
newfiles[i].filepos = file_info.c_offset;
nextfileziphandle = unzGoToNextFile (zip->handle);
if (nextfileziphandle == UNZ_END_OF_LIST_OF_FILE)
break;
else if (nextfileziphandle != UNZ_OK)
Con_Printf("Zip Error\n");
}
zip->references = 1;
zip->currentfile = NULL;
Con_TPrintf (TL_ADDEDZIPFILE, desc, zip->numfiles);
zip->pub.fsver = FSVER;
zip->pub.GetPathDetails = FSZIP_GetPathDetails;
zip->pub.ClosePath = FSZIP_ClosePath;
zip->pub.BuildHash = FSZIP_BuildHash;
zip->pub.FindFile = FSZIP_FLocate;
zip->pub.ReadFile = FSZIP_ReadFile;
zip->pub.EnumerateFiles = FSZIP_EnumerateFiles;
zip->pub.GeneratePureCRC = FSZIP_GeneratePureCRC;
zip->pub.OpenVFS = FSZIP_OpenVFS;
return &zip->pub;
}
#endif

View File

@ -4,11 +4,16 @@
#endif
#include "com_mesh.h"
#ifdef _WIN32
#include <malloc.h>
#else
#include <alloca.h>
#endif
#define MAX_Q3MAP_INDICES 0x800000 //just a sanity limit
#define MAX_Q3MAP_VERTEXES 0x80000 //just a sanity limit
#define MAX_Q3MAP_BRUSHSIDES 0x30000
#define MAX_CM_BRUSHSIDES (MAX_Q3MAP_BRUSHSIDES << 1)
#define MAX_CM_BRUSHES (MAX_Q2MAP_BRUSHES << 1)
#define MAX_CM_PATCH_VERTS (4096)
#define MAX_CM_FACES (MAX_Q2MAP_FACES)
#define MAX_CM_PATCHES (0x10000)
@ -299,7 +304,7 @@ static int numcmodels;
static cmodel_t map_cmodels[MAX_Q2MAP_MODELS];
static int numbrushes;
static q2cbrush_t map_brushes[MAX_Q2MAP_BRUSHES];
static q2cbrush_t *map_brushes;
static int numvisibility;
static q2dvis_t *map_q2vis;
@ -319,8 +324,9 @@ static q2dareaportal_t map_areaportals[MAX_Q2MAP_AREAPORTALS];
static q3cpatch_t map_patches[MAX_CM_PATCHES];
static int numpatches;
static int map_leafpatches[MAX_CM_LEAFFACES];
static int *map_leafpatches;
static int numleafpatches;
static int maxleafpatches;
static int numclusters = 1;
@ -915,12 +921,12 @@ qboolean CM_CreatePatchesForLeafs (void)
q3cface_t *face;
q2mapsurface_t *surf;
q3cpatch_t *patch;
int checkout[MAX_CM_FACES];
int *checkout = alloca(sizeof(int)*numfaces);
if (map_noCurves.ival)
return true;
memset (checkout, -1, sizeof(int)*MAX_CM_FACES);
memset (checkout, -1, sizeof(int)*numfaces);
for (i = 0, leaf = map_leafs; i < numleafs; i++, leaf++)
{
@ -933,11 +939,19 @@ qboolean CM_CreatePatchesForLeafs (void)
for (j=0 ; j<leaf->numleaffaces ; j++)
{
k = leaf->firstleafface + j;
if (k >= numleaffaces) {
if (k >= numleaffaces)
{
break;
}
k = map_leaffaces[k];
#ifdef _DEBUG
if (k >= numfaces)
{
Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: corrupt map\n");
break;
}
#endif
face = &map_faces[k];
if (face->facetype != MST_PATCH || face->numverts <= 0)
@ -951,10 +965,16 @@ qboolean CM_CreatePatchesForLeafs (void)
if ( !surf->c.value || (surf->c.flags & Q3SURF_NONSOLID) )
continue;
if ( numleafpatches >= MAX_CM_LEAFFACES )
if (numleafpatches >= maxleafpatches)
{
Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map has too many faces\n");
return false;
maxleafpatches *= 2;
maxleafpatches += 16;
if (numleafpatches > maxleafpatches)
{ //detect overflow
Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map is insanely huge!\n");
return false;
}
map_leafpatches = realloc(map_leafpatches, sizeof(*map_leafpatches) * maxleafpatches);
}
// the patch was already built
@ -1436,7 +1456,7 @@ qboolean CMod_LoadNodes (lump_t *l)
Con_Printf (CON_ERROR "Map has no nodes\n");
return false;
}
if (count > MAX_MAP_NODES)
if (count > SANITY_MAX_MAP_NODES)
{
Con_Printf (CON_ERROR "Map has too many nodes\n");
return false;
@ -1499,12 +1519,14 @@ qboolean CMod_LoadBrushes (lump_t *l)
}
count = l->filelen / sizeof(*in);
if (count > MAX_Q2MAP_BRUSHES)
if (count > SANITY_MAX_MAP_BRUSHES)
{
Con_Printf (CON_ERROR "Map has too many brushes");
return false;
}
map_brushes = Hunk_AllocName(sizeof(*out) * (count+1), "brushes");
out = map_brushes;
numbrushes = count;
@ -2210,7 +2232,7 @@ qboolean CModQ3_LoadFaces (lump_t *l)
}
count = l->filelen / sizeof(*in);
if (count > MAX_MAP_FACES)
if (count > SANITY_MAX_MAP_FACES)
{
Con_Printf (CON_ERROR "Map has too many faces\n");
return false;
@ -2251,7 +2273,7 @@ qboolean CModRBSP_LoadFaces (lump_t *l)
}
count = l->filelen / sizeof(*in);
if (count > MAX_MAP_FACES)
if (count > SANITY_MAX_MAP_FACES)
{
Con_Printf (CON_ERROR "Map has too many faces\n");
return false;
@ -2888,7 +2910,7 @@ qboolean CModQ3_LoadLeafFaces (lump_t *l)
}
count = l->filelen / sizeof(*in);
if (count > MAX_Q2MAP_LEAFFACES)
if (count > SANITY_MAX_MAP_LEAFFACES)
{
Con_Printf (CON_ERROR "Map has too many leaffaces\n");
return false;
@ -2930,7 +2952,7 @@ qboolean CModQ3_LoadNodes (lump_t *l)
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
if (count > MAX_MAP_NODES)
if (count > SANITY_MAX_MAP_NODES)
{
Con_Printf (CON_ERROR "Too many nodes on map\n");
return false;
@ -2988,12 +3010,14 @@ qboolean CModQ3_LoadBrushes (lump_t *l)
}
count = l->filelen / sizeof(*in);
if (count > MAX_Q2MAP_BRUSHES)
if (count > SANITY_MAX_MAP_BRUSHES)
{
Con_Printf (CON_ERROR "Map has too many brushes");
return false;
}
map_brushes = Hunk_AllocName(sizeof(*out) * (count+1), "brushes");
out = map_brushes;
numbrushes = count;
@ -4295,7 +4319,7 @@ void CM_InitBoxHull (void)
box_model.nodes = Hunk_Alloc(sizeof(mnode_t)*6);
box_planes = &map_planes[numplanes];
if (numbrushes+1 > MAX_Q2MAP_BRUSHES
if (numbrushes+1 > SANITY_MAX_MAP_BRUSHES
|| numleafbrushes+1 > MAX_Q2MAP_LEAFBRUSHES
|| numbrushsides+6 > MAX_Q2MAP_BRUSHSIDES
|| numplanes+12 > MAX_Q2MAP_PLANES)

View File

@ -86,7 +86,7 @@ void NET_Init (void);
void SVNET_RegisterCvars(void);
void NET_InitClient (void);
void NET_InitServer (void);
qboolean NET_WasSpecialPacket(void);
qboolean NET_WasSpecialPacket(netsrc_t netsrc);
void NET_CloseServer (void);
void UDP_CloseSocket (int socket);
void NET_Shutdown (void);

View File

@ -86,7 +86,7 @@ cvar_t showdrop = SCVAR("showdrop", "0");
cvar_t qport = SCVAR("qport", "0");
cvar_t net_mtu = CVARD("net_mtu", "1450", "Specifies a maximum udp payload size, above which packets will be fragmented. If routers all worked properly this could be some massive value, and some massive value may work really nicely for lans. Use smaller values than the default if you're connecting through nested tunnels through routers that fail with IP fragmentation.");
cvar_t pext_replacementdeltas = CVAR("debug_pext_replacementdeltas", "1"); /*rename once the extension is finalized*/
cvar_t pext_replacementdeltas = CVAR("pext_replacementdeltas", "1");
/*returns the entire bitmask of supported+enabled extensions*/
unsigned int Net_PextMask(int maskset, qboolean fornq)

View File

@ -1,5 +1,7 @@
#include "quakedef.h"
#if defined(_WIN32) && !defined(_SDL) && defined(HAVE_SSL)
cvar_t *tls_ignorecertificateerrors;
#include <windows.h>
#define SECURITY_WIN32
#include <security.h>
@ -48,6 +50,8 @@ static qboolean SSL_Init(void)
{(void**)&crypt.pCertFreeCertificateChain, "CertFreeCertificateChain"},
{NULL, NULL}
};
tls_ignorecertificateerrors = Cvar_Get("tls_ignorecertificateerrors", "0", CVAR_NOTFROMSERVER, "TLS");
if (!secur.lib)
secur.lib = Sys_LoadLibrary("secur32.dll", secur_functable);
@ -174,6 +178,8 @@ static void SSPI_Decode(sslfile_t *f)
if (ss < 0)
{
if (ss == SEC_E_INCOMPLETE_MESSAGE)
return; //no error if its incomplete, we can just get more data later on.
SSPI_Error(f, "DecryptMessage failed");
return;
}
@ -351,7 +357,13 @@ static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServe
case CERT_E_WRONG_USAGE: err = "CERT_E_WRONG_USAGE"; break;
default: err = "(unknown)"; break;
}
Sys_Printf("Error verifying certificate for %s: %s\n", pwszServerName, err);
Con_Printf("Error verifying certificate for '%S': %s\n", pwszServerName, err);
if (tls_ignorecertificateerrors->ival)
{
Con_Printf("pretending it didn't happen... (tls_ignorecertificateerrors is set)\n");
Status = SEC_E_OK;
}
}
else
Status = SEC_E_OK;

View File

@ -516,8 +516,11 @@ char *NET_AdrToString (char *s, int len, netadr_t *a)
*s = 0;
doneblank = false;
p = s;
snprintf (s, len-strlen(s), "[");
p += strlen(p);
if (a->port)
{
snprintf (s, len-strlen(s), "[");
p += strlen(p);
}
for (i = 0; i < 16; i+=2)
{
@ -554,8 +557,9 @@ char *NET_AdrToString (char *s, int len, netadr_t *a)
}
}
snprintf (p, len-strlen(s), "]:%i",
ntohs(a->port));
if (a->port)
snprintf (p, len-strlen(s), "]:%i",
ntohs(a->port));
break;
#endif
#ifdef USEIPX
@ -2422,6 +2426,9 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i
setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&_true, sizeof(_true));
#endif
setsockopt(newsocket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&_true, sizeof(_true));
bufsz = 1<<18;
setsockopt(newsocket, SOL_SOCKET, SO_RCVBUF, (void*)&bufsz, sizeof(bufsz));
@ -2573,7 +2580,7 @@ void tobase64(unsigned char *out, int outlen, unsigned char *in, int inlen)
}
#include "fs.h"
int SHA1(char *digest, int maxdigestsize, char *string);
int SHA1(char *digest, int maxdigestsize, char *string, int stringlen);
qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon)
{
ftenet_tcpconnect_connection_t *con = (ftenet_tcpconnect_connection_t*)gcon;
@ -2810,10 +2817,12 @@ closesvstream:
{
char acceptkey[20*2];
unsigned char sha1digest[20];
char *blurgh;
memmove(st->inbuffer, st->inbuffer+i, st->inlen - (i));
st->inlen -= i;
tobase64(acceptkey, sizeof(acceptkey), sha1digest, SHA1(sha1digest, sizeof(sha1digest), va("%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", arg[WCATTR_WSKEY])));
blurgh = va("%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", arg[WCATTR_WSKEY]);
tobase64(acceptkey, sizeof(acceptkey), sha1digest, SHA1(sha1digest, sizeof(sha1digest), blurgh, strlen(blurgh)));
Con_Printf("Websocket request for %s from %s\n", arg[WCATTR_URL], NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
@ -4451,6 +4460,9 @@ int TCP_OpenStream (netadr_t *remoteaddr)
setsockopt(newsocket, SOL_SOCKET, SO_RCVBUF, (void*)&recvbufsize, sizeof(recvbufsize));
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno));
// memset(&loc, 0, sizeof(loc));
// ((struct sockaddr*)&loc)->sa_family = ((struct sockaddr*)&loc)->sa_family;
// bind(newsocket, (struct sockaddr *)&loc, ((struct sockaddr_in*)&qs)->sin_family == AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6));
@ -4458,27 +4470,26 @@ int TCP_OpenStream (netadr_t *remoteaddr)
if (connect(newsocket, (struct sockaddr *)&qs, temp) == INVALID_SOCKET)
{
int err = qerrno;
if (err == EADDRNOTAVAIL)
if (err != EWOULDBLOCK)
{
char buf[128];
NET_AdrToString(buf, sizeof(buf), remoteaddr);
if (remoteaddr->port == 0 && (remoteaddr->type == NA_IP || remoteaddr->type == NA_IPV6))
Con_Printf ("TCP_OpenStream: no port specified\n");
if (err == EADDRNOTAVAIL)
{
char buf[128];
NET_AdrToString(buf, sizeof(buf), remoteaddr);
if (remoteaddr->port == 0 && (remoteaddr->type == NA_IP || remoteaddr->type == NA_IPV6))
Con_Printf ("TCP_OpenStream: no port specified\n");
else
Con_Printf ("TCP_OpenStream: invalid address trying to connect to %s\n", buf);
}
else if (err == EACCES)
Con_Printf ("TCP_OpenStream: access denied: check firewall\n");
else
Con_Printf ("TCP_OpenStream: invalid address trying to connect to %s\n", buf);
Con_Printf ("TCP_OpenStream: connect: error %i\n", err);
closesocket(newsocket);
return INVALID_SOCKET;
}
else if (err == EACCES)
Con_Printf ("TCP_OpenStream: access denied: check firewall\n");
else
Con_Printf ("TCP_OpenStream: connect: error %i\n", err);
closesocket(newsocket);
return INVALID_SOCKET;
}
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno));
return newsocket;
#endif
}
@ -4856,6 +4867,224 @@ void NET_GetLocalAddress (int socket, netadr_t *out)
#endif
}
#ifdef SUPPORT_ICE
static struct icestate_s *icelist;
struct icestate_s *QDECL ICE_Find(void *module, char *conname)
{
struct icestate_s *con;
for (con = icelist; con; con = con->next)
{
if (con->module == module && !strcmp(con->conname, conname))
return con;
}
return NULL;
}
struct icestate_s *QDECL ICE_Create(void *module, char *conname, char *peername, enum icemode_e mode)
{
ftenet_connections_t *collection;
struct icestate_s *con;
int netsrc;
if (conname)
if (ICE_Find(module, conname))
return NULL;
if (!conname)
{
#ifdef SERVERONLY
return NULL;
#else
int rnd[2];
Sys_RandomBytes((void*)rnd, sizeof(rnd));
conname = va("fte%08x%08x", rnd[0], rnd[1]);
collection = cls.sockets; //initiator is ALWAYS the game client.
netsrc = NS_CLIENT;
#endif
}
else
{
#ifdef CLIENTONLY
return NULL;
#else
collection = svs.sockets; //responder is ALWAYS the game server.
netsrc = NS_SERVER;
#endif
}
con = Z_Malloc(sizeof(*con));
con->conname = Z_StrDup(conname);
con->friendlyname = Z_StrDup(peername);
con->netsrc = netsrc;
con->mode = mode;
con->mode = ICE_RAW;
con->next = icelist;
icelist = con;
{
int rnd[1]; //'must have at least 24 bits randomness'
Sys_RandomBytes((void*)rnd, sizeof(rnd));
con->lfrag = Z_StrDup(va("%08x", rnd[0]));
}
{
int rnd[4]; //'must have at least 128 bits randomness'
Sys_RandomBytes((void*)rnd, sizeof(rnd));
con->lpwd = Z_StrDup(va("%08x%08x%08x%08x", rnd[0], rnd[1], rnd[2], rnd[3]));
}
if (collection)
{
int i;
int adrno, adrcount=1;
netadr_t adr;
char adrbuf[MAX_ADR_SIZE];
int net = 0;
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if (!collection->conn[i])
continue;
adrno = 0;
if (collection->conn[i]->GetLocalAddress)
{
for (adrcount=1; (adrcount = collection->conn[i]->GetLocalAddress(collection->conn[i], &adr, adrno)) && adrno < adrcount; adrno++)
{
struct icecandidate_s *cand;
int rnd[2];
if (adr.type == NA_IP || adr.type == NA_IPV6)
{
cand = Z_Malloc(sizeof(*cand));
cand->network = net;
cand->port = ntohs(adr.port);
adr.port = 0; //to make sure its not part of the string...
cand->addr = Z_StrDup(NET_AdrToString(adrbuf, sizeof(adrbuf), &adr));
cand->generation = 0;
cand->component = 1;
cand->foundation = 1;
cand->priority =
(1<<24)*(126) +
(1<<8)*((adr.type == NA_IP?32768:0)+net*256+(255-adrcount)) +
(1<<0)*(256 - cand->component);
Sys_RandomBytes((void*)rnd, sizeof(rnd));
cand->candidateid = Z_StrDup(va("x%08x%08x", rnd[0], rnd[1]));
cand->dirty = true;
cand->next = con->lc;
con->lc = cand;
}
}
}
net++;
}
}
return con;
}
void QDECL ICE_Begin(struct icestate_s *con, char *stunip, int stunport)
{
switch(con->mode)
{
case ICE_RAW:
//info is already as complete as it'll ever be... yeah, it sucks. sue me.
if (con->netsrc == NS_CLIENT)
{
struct icecandidate_s *rc;
rc = con->rc;//for (rc = con->rc; rc;
if (rc && (!strchr(rc->addr, ';') && !strchr(rc->addr, '\n')))
Cbuf_AddText(va("connect [%s]:%i\n", rc->addr, rc->port), RESTRICT_LOCAL);
else
Con_Printf("Remote candidate is not valid\n");
}
break;
case ICE_ICE:
//FIXME: schedule some stun requests to some public stun server
break;
}
}
struct icecandidate_s *QDECL ICE_GetLCandidateInfo(struct icestate_s *con)
{
struct icecandidate_s *can;
for (can = con->lc; can; can = can->next)
{
if (can->dirty)
{
can->dirty = false;
return can;
}
}
return NULL;
}
void QDECL ICE_AddRCandidateInfo(struct icestate_s *con, struct icecandidate_s *n)
{
struct icecandidate_s *o;
for (o = con->rc; o; o = o->next)
{
if (!strcmp(o->candidateid, n->candidateid))
break;
}
if (!o)
{
o = Z_Malloc(sizeof(*o));
o->next = con->rc;
con->rc = o;
o->candidateid = Z_StrDup(n->candidateid);
}
else
{
Z_Free(o->addr);
}
o->addr = Z_StrDup(n->addr);
o->port = n->port;
o->type = n->type;
o->priority = n->priority;
o->network = n->network;
o->generation = n->generation;
o->foundation = n->foundation;
o->component = n->component;
o->transport = n->transport;
}
static void ICE_Destroy(struct icestate_s *con)
{
//has already been unlinked
Z_Free(con);
}
void QDECL ICE_Close(struct icestate_s *con)
{
struct icestate_s **link;
for (link = &icelist; *link; )
{
if (con == *link)
{
*link = con->next;
ICE_Destroy(con);
return;
}
else
link = &(*link)->next;
}
}
void QDECL ICE_CloseModule(void *module)
{
struct icestate_s **link, *con;
for (link = &icelist; *link; )
{
con = *link;
if (con->module == module)
{
*link = con->next;
ICE_Destroy(con);
}
else
link = &(*link)->next;
}
}
#endif
#ifndef CLIENTONLY
void SVNET_AddPort_f(void)
{
@ -4896,7 +5125,7 @@ typedef struct
unsigned short attrtype;
unsigned short attrlen;
} stunattr_t;
static qboolean NET_WasStun(void)
static qboolean NET_WasStun(netsrc_t netsrc)
{
if ((net_from.type == NA_IP || net_from.type == NA_IPV6) && net_message.cursize >= 20)
{
@ -4904,6 +5133,7 @@ static qboolean NET_WasStun(void)
int stunlen = BigShort(stun->msglen);
if (stun->msgtype == BigShort(0x0101) && net_message.cursize == stunlen + sizeof(*stun))
{
//binding reply
stunattr_t *attr = (stunattr_t*)(stun+1);
int alen;
while(stunlen)
@ -4912,30 +5142,100 @@ static qboolean NET_WasStun(void)
alen = BigShort(attr->attrlen);
if (alen > stunlen)
return false;
if (attr->attrtype == BigShort(1) && alen == 8 && ((qbyte*)attr)[5] == 1) //ipv4 MAPPED-ADDRESS
stunlen -= alen;
switch(BigShort(attr->attrtype))
{
netadr_t adr;
char str[256];
adr.type = NA_IP;
adr.port = (((short*)attr)[3]);
memcpy(adr.address.ip, &((qbyte*)attr)[8], 4);
NET_AdrToString(str, sizeof(str), &adr);
Con_Printf("Public address %s\n", str);
}
else if (attr->attrtype == BigShort(1) && alen == 20 && ((qbyte*)attr)[5] == 2) //ipv6 MAPPED-ADDRESS
{
netadr_t adr;
char str[256];
adr.type = NA_IPV6;
adr.port = (((short*)attr)[3]);
memcpy(adr.address.ip6, &((qbyte*)attr)[8], 16);
NET_AdrToString(str, sizeof(str), &adr);
Con_Printf("Public address %s\n", str);
case 1:
if (alen == 8 && ((qbyte*)attr)[5] == 1) //ipv4 MAPPED-ADDRESS
{
netadr_t adr;
char str[256];
adr.type = NA_IP;
adr.port = (((short*)attr)[3]);
memcpy(adr.address.ip, &((qbyte*)attr)[8], 4);
NET_AdrToString(str, sizeof(str), &adr);
Con_Printf("Public address %s\n", str);
}
else if (alen == 20 && ((qbyte*)attr)[5] == 2) //ipv6 MAPPED-ADDRESS
{
netadr_t adr;
char str[256];
adr.type = NA_IPV6;
adr.port = (((short*)attr)[3]);
memcpy(adr.address.ip6, &((qbyte*)attr)[8], 16);
NET_AdrToString(str, sizeof(str), &adr);
Con_Printf("Public address %s\n", str);
}
break;
}
attr = (stunattr_t*)((char*)(attr+1) + alen);
}
return true;
}
else if (stun->msgtype == BigShort(0x0001) && net_message.cursize == stunlen + sizeof(*stun))
{
char username[256];
//binding request
stunattr_t *attr = (stunattr_t*)(stun+1);
int alen;
*username = 0;
while(stunlen)
{
alen = (unsigned short)BigShort(attr->attrlen);
if (alen+sizeof(*attr) > stunlen)
return false;
switch((unsigned short)BigShort(attr->attrtype))
{
case 0x6:
//username
if (alen < sizeof(username))
{
memcpy(username, attr+1, alen);
username[alen] = 0;
Con_Printf("Stun username = \"%s\"\n", username);
}
break;
case 0x8:
//message integrity
Con_Printf("integrity = \"%08x%08x%08x%08x%08x\"\n", BigLong(*(int*)(attr+1)), BigLong(*(int*)(attr+2)), BigLong(*(int*)(attr+3)), BigLong(*(int*)(attr+4)), BigLong(*(int*)(attr+5)));
break;
case 0x24:
//priority
Con_Printf("priority = \"%i\"\n", BigLong(*(int*)(attr+1)));
break;
case 0x8028:
//fingerprint
Con_Printf("fingerprint = \"%08x\"\n", BigLong(*(int*)(attr+1)));
break;
case 0x8029:
//ice controlled
Con_Printf("tie breaker = \"%08x%08x\"\n", BigLong(*(int*)(attr+1)), BigLong(*(int*)(attr+2)));
break;
}
alen = (alen+3)&~3;
attr = (stunattr_t*)((char*)(attr+1) + alen);
stunlen -= alen+sizeof(*attr);
}
{
struct {
stunhdr_t hdr;
stunattr_t unattr;
char uname[256];
} stunmsg;
stunmsg.hdr.magiccookie = BigLong(0x2112a442);
Sys_RandomBytes((qbyte*)&stunmsg.hdr.transactid[0], sizeof(stunmsg.hdr.transactid)); // 'and SHOULD be cryptographically random'
stunmsg.hdr.msgtype = BigShort(0x0101); //binding result
strcpy(stunmsg.uname, username);
stunmsg.unattr.attrtype = BigShort(0x6);
stunmsg.unattr.attrlen = BigShort(strlen(stunmsg.uname));
stunmsg.hdr.msglen = BigShort(sizeof(stunmsg.unattr)+(strlen(stunmsg.uname)+3)&~3);
NET_SendPacket(netsrc, sizeof(stunmsg.hdr) + BigShort(stunmsg.hdr.msglen), &stunmsg, &net_from);
}
return true;
}
}
return false;
}
@ -4972,14 +5272,29 @@ void NET_ClientPort_f(void)
}
#endif
qboolean NET_WasSpecialPacket(void)
qboolean NET_WasSpecialPacket(netsrc_t netsrc)
{
ftenet_connections_t *collection = NULL;
if (netsrc == NS_SERVER)
{
#ifndef CLIENTONLY
if (NET_WasStun())
collection = svs.sockets;
#endif
}
else
{
#ifndef SERVERONLY
collection = cls.sockets;
#endif
}
#ifndef CLIENTONLY
if (NET_WasStun(netsrc))
return true;
#endif
#ifdef HAVE_NATPMP
if (NET_Was_NATPMP(svs.sockets))
if (NET_Was_NATPMP(collection))
return true;
#endif
return false;
@ -5259,7 +5574,8 @@ void NET_Shutdown (void)
typedef struct {
vfsfile_t funcs;
int sock;
SOCKET sock;
qboolean conpending;
char readbuffer[65536];
int readbuffered;
@ -5278,6 +5594,19 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
int len;
int trying;
if (tf->conpending)
{
fd_set fd;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
FD_ZERO(&fd);
FD_SET(tf->sock, &fd);
if (!select((int)tf->sock, NULL, &fd, NULL, &timeout))
return 0;
tf->conpending = false;
}
if (tf->sock != INVALID_SOCKET)
{
trying = sizeof(tf->readbuffer) - tf->readbuffered;
@ -5294,6 +5623,12 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
case ECONNABORTED:
Sys_Printf("connection aborted\n", e);
break;
case ECONNREFUSED:
Sys_Printf("connection refused\n", e);
break;
case ECONNRESET:
Sys_Printf("connection reset\n", e);
break;
default:
Sys_Printf("socket error %i\n", e);
}
@ -5340,9 +5675,29 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
if (tf->sock == INVALID_SOCKET)
return 0;
if (tf->conpending)
{
fd_set fd;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
FD_ZERO(&fd);
FD_SET(tf->sock, &fd);
if (!select((int)tf->sock, NULL, &fd, NULL, &timeout))
return 0;
tf->conpending = false;
}
len = send(tf->sock, buffer, bytestoread, 0);
if (len == -1 || len == 0)
{
int e = qerrno;
switch(e)
{
default:
Sys_Printf("socket error %i\n", e);
break;
}
// don't destroy it on write errors, because that prevents us from reading anything that was sent to us afterwards.
// instead let the read handling kill it if there's nothing new to be read
VFSTCP_ReadBytes(file, NULL, 0);
@ -5382,6 +5737,7 @@ vfsfile_t *FS_OpenTCP(const char *name, int defaultport)
return NULL;
newf = Z_Malloc(sizeof(*newf));
newf->conpending = true;
newf->sock = sock;
newf->funcs.Close = VFSTCP_Close;
newf->funcs.Flush = NULL;

View File

@ -38,7 +38,11 @@
#ifdef _MSC_VER
#define USEIPX
#endif
#include "winquake.h"
#define WIN32_LEAN_AND_MEAN
#define byte winbyte
#include <windows.h>
#include <winsock2.h>
// #include "winquake.h"
#ifdef USEIPX
#include "wsipx.h"
#endif
@ -191,3 +195,60 @@
#undef IPPROTO_IPV6
#endif
#if 1//def SUPPORT_ICE
struct icecandidate_s
{
struct icecandidate_s *next;
char *candidateid;
char *addr; //v4/v6/fqdn. fqdn should prefer ipv6
int port;
int transport; //0=udp. other values not supported
int foundation; //to figure out...
int component; //1-based. allows rtp+rtcp in a single ICE... we only support one.
int priority; //some random value...
enum
{
ICE_HOST=0,
ICE_SRFLX=1,
ICE_PRFLX=2,
ICE_RELAY=3,
} type; //says what sort of proxy is used.
char *reladdr; //when proxied, this is our local info
int relport;
int generation; //for ice restarts. starts at 0.
int network; //which network device this comes from.
qboolean dirty;
};
struct icestate_s
{
struct icestate_s *next;
void *module;
int netsrc;
enum icemode_e
{
ICE_RAW, //not actually interactive beyond a simple handshake.
ICE_ICE //rfc5245. meant to be able to holepunch, but not implemented properly yet.
} mode;
char *conname; //internal id.
char *friendlyname; //who you're talking to.
char *stunserver;//where to get our public ip from.
int stunport;
struct icecandidate_s *lc;
char *lpwd;
char *lfrag;
struct icecandidate_s *rc;
char *rpwd;
char *rfrag;
};
struct icestate_s *QDECL ICE_Create(void *module, char *conname, char *peername, enum icemode_e mode); //doesn't start pinging anything.
struct icestate_s *QDECL ICE_Find(void *module, char *conname);
void QDECL ICE_Begin(struct icestate_s *con, char *stunip, int stunport); //begins sending stun packets and stuff as required. data flows automagically. caller should poll ICE_GetLCandidateInfo periodically to pick up new candidates that need to be reported to the peer.
struct icecandidate_s *QDECL ICE_GetLCandidateInfo(struct icestate_s *con); //retrieves candidates that need reporting to the peer.
void QDECL ICE_AddRCandidateInfo(struct icestate_s *con, struct icecandidate_s *cand); //stuff that came from the peer.
void QDECL ICE_Close(struct icestate_s *con); //bye then.
void QDECL ICE_CloseModule(void *module); //closes all unclosed connections, with warning.
#endif

View File

@ -128,6 +128,7 @@ typedef struct plugin_s {
int tick;
int executestring;
#ifndef SERVERONLY
int consolelink;
int conexecutecommand;
int menufunction;
int sbarlevel[3]; //0 - main sbar, 1 - supplementry sbar sections (make sure these can be switched off), 2 - overlays (scoreboard). menus kill all.
@ -203,6 +204,27 @@ void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags)
plugbuiltins[newnum].flags = flags;
}
static qintptr_t VARGS Plug_GetNativePointer(void *offset, quintptr_t mask, const qintptr_t *args)
{
char *p = (char *)VM_POINTER(args[0]);
#ifdef SUPPORT_ICE
if (!strcmp(p, "ICE_Create"))
return (qintptr_t)ICE_Create;
if (!strcmp(p, "ICE_Find"))
return (qintptr_t)ICE_Find;
if (!strcmp(p, "ICE_Begin"))
return (qintptr_t)ICE_Begin;
if (!strcmp(p, "ICE_GetLCandidateInfo"))
return (qintptr_t)ICE_GetLCandidateInfo;
if (!strcmp(p, "ICE_AddRCandidateInfo"))
return (qintptr_t)ICE_AddRCandidateInfo;
if (!strcmp(p, "ICE_Close"))
return (qintptr_t)ICE_Close;
#endif
return (qintptr_t)NULL;
}
/*
static void Plug_RegisterBuiltinIndex(char *name, Plug_Builtin_t bi, int flags, int index) //I d
{
@ -408,13 +430,15 @@ static qintptr_t VARGS Plug_ExportToEngine(void *offset, quintptr_t mask, const
char *name = (char*)VM_POINTER(arg[0]);
unsigned int functionid = VM_LONG(arg[1]);
if (!strcmp(name, "Tick"))
if (!strcmp(name, "Tick")) //void(int realtime)
currentplug->tick = functionid;
else if (!strcmp(name, "ExecuteCommand"))
else if (!strcmp(name, "ExecuteCommand")) //bool(isinsecure)
currentplug->executestring = functionid;
else if (!strcmp(name, "Shutdown"))
else if (!strcmp(name, "Shutdown")) //void()
currentplug->shutdown = functionid;
#ifndef SERVERONLY
else if (!strcmp(name, "ConsoleLink"))
currentplug->consolelink = functionid;
else if (!strcmp(name, "ConExecuteCommand"))
currentplug->conexecutecommand = functionid;
else if (!strcmp(name, "MenuEvent"))
@ -657,13 +681,21 @@ static qintptr_t VARGS Plug_Cvar_GetFloat(void *offset, quintptr_t mask, const q
{
char *name = VM_POINTER(arg[0]);
int ret;
cvar_t *var = Cvar_Get(name, "", 0, "Plugin vars");
if (var)
{
VM_FLOAT(ret) = var->value;
}
cvar_t *var;
#ifndef CLIENTONLY
if (!strcmp(name, "sv.state"))
VM_FLOAT(ret) = sv.state;
else
VM_FLOAT(ret) = 0;
#endif
{
var = Cvar_Get(name, "", 0, "Plugin vars");
if (var)
{
VM_FLOAT(ret) = var->value;
}
else
VM_FLOAT(ret) = 0;
}
return ret;
}
@ -682,12 +714,22 @@ static qintptr_t VARGS Plug_Cvar_GetString(void *offset, quintptr_t mask, const
ret = VM_POINTER(arg[1]);
retsize = VM_LONG(arg[2]);
if (!strcmp(name, "sv.mapname"))
{
#ifdef CLIENTONLY
Q_strncpyz(ret, "", retsize);
#else
Q_strncpyz(ret, sv.name, retsize);
#endif
}
else
{
var = Cvar_Get(name, "", 0, "Plugin vars");
if (strlen(var->name)+1 > retsize)
return false;
var = Cvar_Get(name, "", 0, "Plugin vars");
if (strlen(var->name)+1 > retsize)
return false;
strcpy(ret, var->string);
strcpy(ret, var->string);
}
return true;
}
@ -725,7 +767,7 @@ void Plug_Command_f(void)
currentplug = plugincommandarray[i].plugin;
if (currentplug->executestring)
VM_Call(currentplug->vm, currentplug->executestring, 0);
VM_Call(currentplug->vm, currentplug->executestring, Cmd_IsInsecure(), 0, 0, 0);
break;
}
@ -1090,6 +1132,7 @@ qintptr_t VARGS Plug_FS_Open(void *offset, quintptr_t mask, const qintptr_t *arg
//char *data;
char *mode;
vfsfile_t *f;
char *fname = VM_POINTER(arg[0]);
if (VM_OOB(arg[1], sizeof(int)))
return -2;
@ -1106,7 +1149,10 @@ qintptr_t VARGS Plug_FS_Open(void *offset, quintptr_t mask, const qintptr_t *arg
default:
return -2;
}
f = FS_OpenVFS(VM_POINTER(arg[0]), mode, FS_GAME);
if (!strcmp(fname, "**plugconfig"))
f = FS_OpenVFS(va("%s.cfg", currentplug->name), mode, FS_ROOT);
else
f = FS_OpenVFS(fname, mode, FS_GAME);
if (!f)
return -1;
handle = Plug_NewStreamHandle(STREAM_VFS);
@ -1458,6 +1504,7 @@ void Plug_Initialise(qboolean fromgamedir)
Cmd_AddCommand("plug_load", Plug_Load_f);
Cmd_AddCommand("plug_list", Plug_List_f);
Plug_RegisterBuiltin("Plug_GetNativePointer", Plug_GetNativePointer, 0);//plugin wishes to find a builtin number.
Plug_RegisterBuiltin("Plug_GetEngineFunction", Plug_GetBuiltin, 0);//plugin wishes to find a builtin number.
Plug_RegisterBuiltin("Plug_ExportToEngine", Plug_ExportToEngine, 0); //plugin has a call back that we might be interested in.
Plug_RegisterBuiltin("Plug_ExportNative", Plug_ExportNative, PLUG_BIF_DLLONLY);
@ -1580,13 +1627,30 @@ qboolean Plugin_ExecuteString(void)
}
#ifndef SERVERONLY
qboolean Plug_ConsoleLink(char *text, char *info)
{
plugin_t *oldplug = currentplug;
for (currentplug = plugs; currentplug; currentplug = currentplug->next)
{
if (currentplug->consolelink)
{
char buffer[2048];
Q_strncpyz(buffer, va("\"%s\" \"%s\"", text, info), sizeof(buffer));
Cmd_TokenizeString(buffer, false, false);
VM_Call(currentplug->vm, currentplug->consolelink);
}
}
currentplug = oldplug;
return false;
}
void Plug_SubConsoleCommand(console_t *con, char *line)
{
char buffer[2048];
plugin_t *oldplug = currentplug; //shouldn't really be needed, but oh well
currentplug = con->userdata;
Q_strncpyz(buffer, va("%s %s", con->name, line), sizeof(buffer));
Q_strncpyz(buffer, va("\"%s\" %s", con->name, line), sizeof(buffer));
Cmd_TokenizeString(buffer, false, false);
VM_Call(currentplug->vm, currentplug->conexecutecommand, 0);
currentplug = oldplug;
@ -1653,13 +1717,12 @@ int Plug_ConnectionlessClientPacket(char *buffer, int size)
}
#endif
#ifndef SERVERONLY
void Plug_SBar(void)
void Plug_SBar(playerview_t *pv)
{
extern qboolean sb_showscores, sb_showteamscores;
plugin_t *oc=currentplug;
int cp, ret;
vrect_t rect;
int ret;
if (!Sbar_ShouldDraw())
return;
@ -1673,31 +1736,24 @@ void Plug_SBar(void)
{
if (currentplug->sbarlevel[0])
{
for (cp = 0; cp < cl.splitclients; cp++)
{ //if you don't use splitscreen, use a full videosize rect.
SCR_VRectForPlayer(&rect, cp);
R2D_ImageColours(1, 1, 1, 1); // ensure menu colors are reset
ret |= VM_Call(currentplug->vm, currentplug->sbarlevel[0], cp, rect.x, rect.y, rect.width, rect.height, sb_showscores+sb_showteamscores*2);
}
//if you don't use splitscreen, use a full videosize rect.
R2D_ImageColours(1, 1, 1, 1); // ensure menu colors are reset
ret |= VM_Call(currentplug->vm, currentplug->sbarlevel[0], pv-cl.playerview, r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, sb_showscores+sb_showteamscores*2);
break;
}
}
}
if (!(ret & 1))
{
Sbar_Draw();
Sbar_Draw(pv);
}
for (currentplug = plugs; currentplug; currentplug = currentplug->next)
{
if (currentplug->sbarlevel[1])
{
for (cp = 0; cp < cl.splitclients; cp++)
{ //if you don't use splitscreen, use a full videosize rect.
SCR_VRectForPlayer(&rect, cp);
R2D_ImageColours(1, 1, 1, 1); // ensure menu colors are reset
ret |= VM_Call(currentplug->vm, currentplug->sbarlevel[1], cp, rect.x, rect.y, rect.width, rect.height, sb_showscores+sb_showteamscores*2);
}
R2D_ImageColours(1, 1, 1, 1); // ensure menu colors are reset
ret |= VM_Call(currentplug->vm, currentplug->sbarlevel[1], pv-cl.playerview, r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, sb_showscores+sb_showteamscores*2);
}
}
@ -1705,16 +1761,12 @@ void Plug_SBar(void)
{
if (currentplug->sbarlevel[2])
{
for (cp = 0; cp < cl.splitclients; cp++)
{ //if you don't use splitscreen, use a full videosize rect.
SCR_VRectForPlayer(&rect, cp);
R2D_ImageColours(1, 1, 1, 1); // ensure menu colors are reset
ret |= VM_Call(currentplug->vm, currentplug->sbarlevel[2], cp, rect.x, rect.y, rect.width, rect.height, sb_showscores+sb_showteamscores*2);
}
R2D_ImageColours(1, 1, 1, 1); // ensure menu colors are reset
ret |= VM_Call(currentplug->vm, currentplug->sbarlevel[2], pv-cl.playerview, r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, sb_showscores+sb_showteamscores*2);
}
}
if (!(ret & 2))
if (!(ret & 2) && pv == cl.playerview)
{
Sbar_DrawScoreboard();
}

View File

@ -1023,11 +1023,10 @@ void QCBUILTIN PF_memptradd (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
//hash table stuff
#define MAX_QC_HASHTABLES 256
#define FIRST_QC_HASHTABLE_INDEX 1
typedef struct
{
pubprogfuncs_t *prinst;
qboolean dupestrings;
hashtable_t tab;
void *bucketmem;
} pf_hashtab_t;
@ -1035,73 +1034,127 @@ typedef struct
{
bucket_t buck;
char *name;
vec3_t data;
union
{
vec3_t data;
char *stringdata;
};
} pf_hashentry_t;
pf_hashtab_t pf_hashtab[MAX_QC_HASHTABLES];
pf_hashtab_t pf_peristanthashtab; //persists over map changes.
pf_hashtab_t pf_reverthashtab; //pf_peristanthashtab as it was at map start, for map restarts.
static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx)
{
if (!idx)
return &pf_peristanthashtab;
idx -= 1;
if (idx >= 0 && idx < MAX_QC_HASHTABLES && pf_hashtab[idx].prinst)
return &pf_hashtab[idx];
else
PR_BIError(prinst, "PF_hash_findtab: invalid hash table\n");
return NULL;
};
void QCBUILTIN PF_hash_getkey (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int tab = G_FLOAT(OFS_PARM0) - FIRST_QC_HASHTABLE_INDEX;
pf_hashtab_t *tab = PF_hash_findtab(prinst, G_FLOAT(OFS_PARM0));
int idx = G_FLOAT(OFS_PARM1);
pf_hashentry_t *ent = NULL;
G_INT(OFS_RETURN) = 0;
if (tab >= 0 && tab < MAX_QC_HASHTABLES && pf_hashtab[tab].prinst)
if (tab)
{
ent = Hash_GetIdx(&pf_hashtab[tab].tab, idx);
ent = Hash_GetIdx(&tab->tab, idx);
if (ent)
RETURN_TSTRING(ent->name);
}
}
void QCBUILTIN PF_hash_delete (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int tab = G_FLOAT(OFS_PARM0) - FIRST_QC_HASHTABLE_INDEX;
pf_hashtab_t *tab = PF_hash_findtab(prinst, G_FLOAT(OFS_PARM0));
char *name = PR_GetStringOfs(prinst, OFS_PARM1);
pf_hashentry_t *ent = NULL;
memset(G_VECTOR(OFS_RETURN), 0, sizeof(vec3_t));
if (tab >= 0 && tab < MAX_QC_HASHTABLES && pf_hashtab[tab].prinst)
if (tab)
{
ent = Hash_Get(&pf_hashtab[tab].tab, name);
ent = Hash_Get(&tab->tab, name);
if (ent)
{
memcpy(G_VECTOR(OFS_RETURN), ent->data, sizeof(vec3_t));
Hash_RemoveData(&pf_hashtab[tab].tab, name, ent);
Hash_RemoveData(&tab->tab, name, ent);
BZ_Free(ent);
}
}
else
PR_BIError(prinst, "PF_hash_get: invalid hash table\n");
}
void QCBUILTIN PF_hash_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int tab = G_FLOAT(OFS_PARM0) - FIRST_QC_HASHTABLE_INDEX;
pf_hashtab_t *tab = PF_hash_findtab(prinst, G_FLOAT(OFS_PARM0));
char *name = PR_GetStringOfs(prinst, OFS_PARM1);
pf_hashentry_t *ent = NULL;
if (tab >= 0 && tab < MAX_QC_HASHTABLES && pf_hashtab[tab].prinst)
if (tab)
{
ent = Hash_Get(&tab->tab, name);
if (ent)
{
if (tab->dupestrings)
{
G_INT(OFS_RETURN+2) = 0;
G_INT(OFS_RETURN+1) = 0;
RETURN_TSTRING(ent->stringdata);
}
else
memcpy(G_VECTOR(OFS_RETURN), ent->data, sizeof(vec3_t));
}
else
memcpy(G_VECTOR(OFS_RETURN), G_VECTOR(OFS_PARM2), sizeof(vec3_t));
}
}
void QCBUILTIN PF_hash_getcb (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
/*
pf_hashtab_t *tab = PF_hash_findtab(prinst, G_FLOAT(OFS_PARM0));
func_t callback = G_FUNCTION(OFS_PARM1);
char *name = PR_GetStringOfs(prinst, OFS_PARM2);
pf_hashentry_t *ent = NULL;
if (tab >= 0 && tab < MAX_QC_HASHTABLES && pf_hashtab[tab].valid)
ent = Hash_Get(&pf_hashtab[tab].tab, name);
else
PR_BIError(prinst, "PF_hash_get: invalid hash table\n");
PR_BIError(prinst, "PF_hash_getcb: invalid hash table\n");
if (ent)
memcpy(G_VECTOR(OFS_RETURN), ent->data, sizeof(vec3_t));
else
memcpy(G_VECTOR(OFS_RETURN), G_VECTOR(OFS_PARM2), sizeof(vec3_t));
*/
}
void QCBUILTIN PF_hash_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int tab = G_FLOAT(OFS_PARM0) - FIRST_QC_HASHTABLE_INDEX;
pf_hashtab_t *tab = PF_hash_findtab(prinst, G_FLOAT(OFS_PARM0));
char *name = PR_GetStringOfs(prinst, OFS_PARM1);
void *data = G_VECTOR(OFS_PARM2);
pf_hashentry_t *ent = NULL;
if (tab >= 0 && tab < MAX_QC_HASHTABLES && pf_hashtab[tab].prinst)
if (tab)
{
int nlen = strlen(name);
ent = BZ_Malloc(sizeof(*ent) + nlen + 1);
ent->name = (char*)(ent+1);
memcpy(ent->name, name, nlen+1);
memcpy(ent->data, data, sizeof(vec3_t));
Hash_Add(&pf_hashtab[tab].tab, ent->name, ent, &ent->buck);
if (tab->dupestrings)
{
char *value = PR_GetStringOfs(prinst, OFS_PARM2);
int nlen = strlen(name);
int vlen = strlen(data);
ent = BZ_Malloc(sizeof(*ent) + nlen+1 + vlen+1);
ent->name = (char*)(ent+1);
ent->stringdata = ent->name+(nlen+1);
memcpy(ent->name, name, nlen+1);
memcpy(ent->stringdata, value, vlen+1);
Hash_Add(&tab->tab, ent->name, ent, &ent->buck);
}
else
{
int nlen = strlen(name);
ent = BZ_Malloc(sizeof(*ent) + nlen + 1);
ent->name = (char*)(ent+1);
memcpy(ent->name, name, nlen+1);
memcpy(ent->data, data, sizeof(vec3_t));
Hash_Add(&tab->tab, ent->name, ent, &ent->buck);
}
}
else
PR_BIError(prinst, "PF_hash_add: invalid hash table\n");
}
static void PF_hash_destroytab_enum(void *ctx, void *ent)
{
@ -1109,28 +1162,30 @@ static void PF_hash_destroytab_enum(void *ctx, void *ent)
}
void QCBUILTIN PF_hash_destroytab (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int tab = G_FLOAT(OFS_PARM0) - FIRST_QC_HASHTABLE_INDEX;
if (tab >= 0 && tab < MAX_QC_HASHTABLES && pf_hashtab[tab].prinst)
pf_hashtab_t *tab = PF_hash_findtab(prinst, G_FLOAT(OFS_PARM0));
if (tab && tab->prinst == prinst)
{
pf_hashtab[tab].prinst = NULL;
Hash_Enumerate(&pf_hashtab[tab].tab, PF_hash_destroytab_enum, NULL);
Z_Free(pf_hashtab[tab].bucketmem);
tab->prinst = NULL;
Hash_Enumerate(&tab->tab, PF_hash_destroytab_enum, NULL);
Z_Free(tab->bucketmem);
}
}
void QCBUILTIN PF_hash_createtab (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int i;
int numbuckets = G_FLOAT(OFS_PARM0);
qboolean dupestrings = (prinst->callargc>1)?G_FLOAT(OFS_PARM1):false;
if (numbuckets < 4)
numbuckets = 64;
for (i = 0; i < MAX_QC_HASHTABLES; i++)
{
if (!pf_hashtab[i].prinst)
{
pf_hashtab[i].dupestrings = dupestrings;
pf_hashtab[i].prinst = prinst;
pf_hashtab[i].bucketmem = Z_Malloc(Hash_BytesForBuckets(numbuckets));
Hash_InitTable(&pf_hashtab[i].tab, numbuckets, pf_hashtab[i].bucketmem);
G_FLOAT(OFS_RETURN) = i + FIRST_QC_HASHTABLE_INDEX;
G_FLOAT(OFS_RETURN) = i + 1;
return;
}
}
@ -1157,11 +1212,32 @@ typedef struct {
} pf_fopen_files_t;
pf_fopen_files_t pf_fopen_files[MAX_QC_FILES];
//returns false if the file is denied.
//fallbackread can be NULL, if the qc is not allowed to read that (original) file at all.
qboolean QC_FixFileName(char *name, char **result, char **fallbackread)
{
if (strchr(name, ':') || //dos/win absolute path, ntfs ADS, amiga drives. reject them all.
strchr(name, '\\') || //windows-only paths.
*name == '/' || //absolute path was given - reject
strstr(name, "..")) //someone tried to be clever.
{
return false;
}
*fallbackread = name;
//if its a user config, ban any fallback locations so that csqc can't read passwords or whatever.
if ((!strchr(name, '/') || strnicmp(name, "configs/", 8)) && !stricmp(COM_FileExtension(name), "cfg"))
*fallbackread = NULL;
*result = va("data/%s", name);
return true;
}
void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *name = PR_GetStringOfs(prinst, OFS_PARM0);
int fmode = G_FLOAT(OFS_PARM1);
int fsize = G_FLOAT(OFS_PARM2);
char *fallbackread;
int i;
for (i = 0; i < MAX_QC_FILES; i++)
@ -1175,15 +1251,14 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
return;
}
if (name[1] == ':' || //dos filename absolute path specified - reject.
strchr(name, '\\') || *name == '/' || //absolute path was given - reject
strstr(name, "..")) //someone tried to be cleaver.
if (!QC_FixFileName(name, &name, &fallbackread))
{
Con_Printf("qcfopen: Access denied: %s\n", name);
G_FLOAT(OFS_RETURN) = -1;
return;
}
Q_strncpyz(pf_fopen_files[i].name, va("data/%s", name), sizeof(pf_fopen_files[i].name));
Q_strncpyz(pf_fopen_files[i].name, name, sizeof(pf_fopen_files[i].name));
pf_fopen_files[i].accessmode = fmode;
switch (fmode)
@ -1222,9 +1297,9 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
case FRIK_FILE_READ: //read
case FRIK_FILE_READNL: //read whole file
pf_fopen_files[i].data = FS_LoadMallocFile(pf_fopen_files[i].name);
if (!pf_fopen_files[i].data)
if (!pf_fopen_files[i].data && fallbackread)
{
Q_strncpyz(pf_fopen_files[i].name, name, sizeof(pf_fopen_files[i].name));
Q_strncpyz(pf_fopen_files[i].name, fallbackread, sizeof(pf_fopen_files[i].name));
pf_fopen_files[i].data = FS_LoadMallocFile(pf_fopen_files[i].name);
}
@ -1694,7 +1769,7 @@ void PR_fclose_progs (pubprogfuncs_t *prinst)
void QCBUILTIN PF_isfunction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *name = PR_GetStringOfs(prinst, OFS_PARM0);
G_FLOAT(OFS_RETURN) = !!PR_FindFunction(prinst, name, PR_CURRENT);
G_FLOAT(OFS_RETURN) = !!PR_FindFunction(prinst, name, PR_ANY);
}
//void callfunction(...)
@ -1706,7 +1781,7 @@ void QCBUILTIN PF_callfunction (pubprogfuncs_t *prinst, struct globalvars_s *pr_
PR_BIError(prinst, "callfunction needs at least one argument\n");
name = PR_GetStringOfs(prinst, OFS_PARM0+(prinst->callargc-1)*3);
prinst->callargc -= 1;
f = PR_FindFunction(prinst, name, PR_CURRENT);
f = PR_FindFunction(prinst, name, PR_ANY);
if (f)
PR_ExecuteProgram(prinst, f);
}
@ -1873,32 +1948,36 @@ void QCBUILTIN PF_print (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
//FTE_STRINGS
//C style strncasecmp (compare first n characters - case insensative)
//C style strcasecmp (case insensative string compare)
void QCBUILTIN PF_strncasecmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *a = PR_GetStringOfs(prinst, OFS_PARM0);
char *b = PR_GetStringOfs(prinst, OFS_PARM1);
int len = G_FLOAT(OFS_PARM2);
int aofs = prinst->callargc>3?G_FLOAT(OFS_PARM3):0;
if (VMUTF8)
if (prinst->callargc > 2)
{
aofs = unicode_byteofsfromcharofs(a, aofs);
len = unicode_byteofsfromcharofs(b, len);
int len = G_FLOAT(OFS_PARM2);
int aofs = prinst->callargc>3?G_FLOAT(OFS_PARM3):0;
int bofs = prinst->callargc>4?G_FLOAT(OFS_PARM4):0;
if (VMUTF8)
{
aofs = aofs?unicode_byteofsfromcharofs(a, aofs):0;
bofs = bofs?unicode_byteofsfromcharofs(b, bofs):0;
len = max(unicode_byteofsfromcharofs(a+aofs, len), unicode_byteofsfromcharofs(b+bofs, len));
}
else
{
if (aofs < 0 || (aofs && aofs > strlen(a)))
aofs = strlen(a);
if (bofs < 0 || (bofs && bofs > strlen(b)))
bofs = strlen(b);
}
G_FLOAT(OFS_RETURN) = Q_strncasecmp(a+aofs, b+bofs, len);
}
else if (aofs < 0 || (aofs && aofs > strlen(a)))
aofs = strlen(a);
G_FLOAT(OFS_RETURN) = strnicmp(a+aofs, b, len);
}
//FTE_STRINGS
//C style strcasecmp (case insensative string compare)
void QCBUILTIN PF_strcasecmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *a = PR_GetStringOfs(prinst, OFS_PARM0);
char *b = PR_GetStringOfs(prinst, OFS_PARM1);
G_FLOAT(OFS_RETURN) = stricmp(a, b);
else
G_FLOAT(OFS_RETURN) = Q_strcasecmp(a, b);
}
//FTE_STRINGS
@ -1907,18 +1986,31 @@ void QCBUILTIN PF_strncmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
{
char *a = PR_GetStringOfs(prinst, OFS_PARM0);
char *b = PR_GetStringOfs(prinst, OFS_PARM1);
int len = G_FLOAT(OFS_PARM2);
int aofs = prinst->callargc>3?G_FLOAT(OFS_PARM3):0;
if (VMUTF8)
if (prinst->callargc > 2)
{
aofs = unicode_byteofsfromcharofs(a, aofs);
len = unicode_byteofsfromcharofs(b, len);
}
else if (aofs < 0 || (aofs && aofs > strlen(a)))
aofs = strlen(a);
int len = G_FLOAT(OFS_PARM2);
int aofs = prinst->callargc>3?G_FLOAT(OFS_PARM3):0;
int bofs = prinst->callargc>4?G_FLOAT(OFS_PARM4):0;
G_FLOAT(OFS_RETURN) = strncmp(a + aofs, b, len);
if (VMUTF8)
{
aofs = aofs?unicode_byteofsfromcharofs(a, aofs):0;
bofs = bofs?unicode_byteofsfromcharofs(b, bofs):0;
len = max(unicode_byteofsfromcharofs(a+aofs, len), unicode_byteofsfromcharofs(b+bofs, len));
}
else
{
if (aofs < 0 || (aofs && aofs > strlen(a)))
aofs = strlen(a);
if (bofs < 0 || (bofs && bofs > strlen(b)))
bofs = strlen(b);
}
G_FLOAT(OFS_RETURN) = Q_strncmp(a + aofs, b, len);
}
else
G_FLOAT(OFS_RETURN) = Q_strcmp(a, b);
}
//uses qw style \key\value strings
@ -2593,6 +2685,7 @@ struct strbuf {
int allocated;
};
#define BUFSTRBASE 1
#define NUMSTRINGBUFS 64
struct strbuf strbuflist[NUMSTRINGBUFS];
@ -2630,17 +2723,17 @@ void QCBUILTIN PF_buf_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
strbuflist[i].used = 0;
strbuflist[i].allocated = 0;
strbuflist[i].strings = NULL;
G_FLOAT(OFS_RETURN) = i+1;
G_FLOAT(OFS_RETURN) = i+BUFSTRBASE;
return;
}
}
G_FLOAT(OFS_RETURN) = 0;
G_FLOAT(OFS_RETURN) = -1;
}
// #441 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_buf_del (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int i;
int bufno = G_FLOAT(OFS_PARM0)-1;
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
@ -2660,7 +2753,7 @@ void QCBUILTIN PF_buf_del (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
// #442 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_buf_getsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int bufno = G_FLOAT(OFS_PARM0)-1;
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
@ -2672,54 +2765,130 @@ void QCBUILTIN PF_buf_getsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_
// #443 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_buf_copy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int buffrom = G_FLOAT(OFS_PARM0)-1;
int bufto = G_FLOAT(OFS_PARM1)-1;
int buffrom = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
int bufto = G_FLOAT(OFS_PARM1)-BUFSTRBASE;
int i;
if (bufto == buffrom) //err...
return;
if ((unsigned int)buffrom >= NUMSTRINGBUFS)
return;
if (strbuflist[buffrom].prinst != prinst)
return;
if ((unsigned int)bufto >= NUMSTRINGBUFS)
return;
if (strbuflist[bufto].prinst != prinst)
return;
Con_Printf("PF_buf_copy: stub\n");
//obliterate any and all existing data.
for (i = 0; i < strbuflist[bufto].used; i++)
Z_Free(strbuflist[bufto].strings[i]);
Z_Free(strbuflist[bufto].strings);
//copy new data over.
strbuflist[bufto].used = strbuflist[bufto].allocated = strbuflist[buffrom].used;
strbuflist[bufto].strings = BZ_Malloc(strbuflist[buffrom].used * sizeof(char*));
for (i = 0; i < strbuflist[buffrom].used; i++)
strbuflist[bufto].strings[i] = strbuflist[buffrom].strings[i]?Z_StrDup(strbuflist[buffrom].strings[i]):NULL;
}
// #444 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
static int PF_buf_sort_sortprefixlen;
static int QDECL PF_buf_sort_ascending(const void *a, const void *b)
{
return strncmp(*(char**)a, *(char**)b, PF_buf_sort_sortprefixlen);
}
static int QDECL PF_buf_sort_descending(const void *b, const void *a)
{
return strncmp(*(char**)a, *(char**)b, PF_buf_sort_sortprefixlen);
}
// #444 void(float bufhandle, float sortprefixlen, float backward) buf_sort (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_buf_sort (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int bufno = G_FLOAT(OFS_PARM0)-1;
//int sortpower = G_FLOAT(OFS_PARM1);
//int backwards = G_FLOAT(OFS_PARM2);
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
int sortprefixlen = G_FLOAT(OFS_PARM1);
int backwards = G_FLOAT(OFS_PARM2);
int s,d;
char **strings;
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
if (strbuflist[bufno].prinst != prinst)
return;
Con_Printf("PF_buf_sort: stub\n");
if (sortprefixlen <= 0)
sortprefixlen = INT_MAX;
//take out the nulls first, to avoid weird/crashy sorting
for (s = 0, d = 0, strings = strbuflist[bufno].strings; s < strbuflist[bufno].used; )
{
if (!strings[s])
{
s++;
continue;
}
strings[d++] = strings[s++];
}
strbuflist[bufno].used = d;
//no nulls now, sort it.
PF_buf_sort_sortprefixlen = sortprefixlen; //eww, a global. burn in hell.
if (backwards) //z first
qsort(strings, strbuflist[bufno].used, sizeof(char*), PF_buf_sort_descending);
else //a first
qsort(strings, strbuflist[bufno].used, sizeof(char*), PF_buf_sort_ascending);
}
// #445 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_buf_implode (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int bufno = G_FLOAT(OFS_PARM0)-1;
//char *glue = PR_GetStringOfs(prinst, OFS_PARM1);
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
char *glue = PR_GetStringOfs(prinst, OFS_PARM1);
unsigned int gluelen = strlen(glue);
unsigned int retlen, l, i;
char **strings;
char *ret;
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
if (strbuflist[bufno].prinst != prinst)
return;
Con_Printf("PF_buf_implode: stub\n");
//count neededlength
strings = strbuflist[bufno].strings;
for (i = 0, retlen = 0; i < strbuflist[bufno].used; i++)
{
if (strings[i])
{
if (retlen)
retlen += gluelen;
retlen += strlen(strings[i]);
}
}
RETURN_TSTRING("");
//generate the output
ret = malloc(retlen+1);
for (i = 0, retlen = 0; i < strbuflist[bufno].used; i++)
{
if (strings[i])
{
if (retlen)
{
memcpy(ret+retlen, glue, gluelen);
retlen += gluelen;
}
l = strlen(strings[i]);
memcpy(ret+retlen, strings[i], l);
retlen += l;
}
}
//add the null and return
ret[retlen] = 0;
RETURN_TSTRING(ret);
free(ret);
}
// #446 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_bufstr_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int bufno = G_FLOAT(OFS_PARM0)-1;
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
int index = G_FLOAT(OFS_PARM1);
if ((unsigned int)bufno >= NUMSTRINGBUFS)
@ -2744,7 +2913,7 @@ void QCBUILTIN PF_bufstr_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
// #447 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_bufstr_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int bufno = G_FLOAT(OFS_PARM0)-1;
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
int index = G_FLOAT(OFS_PARM1);
char *string = PR_GetStringOfs(prinst, OFS_PARM2);
int oldcount;
@ -2769,21 +2938,11 @@ void QCBUILTIN PF_bufstr_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (index >= strbuflist[bufno].used)
strbuflist[bufno].used = index+1;
}
// #448 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_bufstr_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
int PF_bufstr_add_internal(int bufno, char *string, int appendonend)
{
int bufno = G_FLOAT(OFS_PARM0)-1;
char *string = PR_GetStringOfs(prinst, OFS_PARM1);
int order = G_FLOAT(OFS_PARM2);
int index;
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
if (strbuflist[bufno].prinst != prinst)
return;
if (order)
if (appendonend)
{
//add on end
index = strbuflist[bufno].used;
@ -2815,12 +2974,27 @@ void QCBUILTIN PF_bufstr_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (index >= strbuflist[bufno].used)
strbuflist[bufno].used = index+1;
G_FLOAT(OFS_RETURN) = index;
return index;
}
// #448 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_bufstr_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
char *string = PR_GetStringOfs(prinst, OFS_PARM1);
int order = G_FLOAT(OFS_PARM2);
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
if (strbuflist[bufno].prinst != prinst)
return;
G_FLOAT(OFS_RETURN) = PF_bufstr_add_internal(bufno, string, order);
}
// #449 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
void QCBUILTIN PF_bufstr_free (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int bufno = G_FLOAT(OFS_PARM0)-1;
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
int index = G_FLOAT(OFS_PARM1);
if ((unsigned int)bufno >= NUMSTRINGBUFS)
@ -2838,16 +3012,109 @@ void QCBUILTIN PF_bufstr_free (pubprogfuncs_t *prinst, struct globalvars_s *pr_
void QCBUILTIN PF_buf_cvarlist (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int bufno = G_FLOAT(OFS_PARM0)-1;
//char *pattern = PR_GetStringOfs(prinst, OFS_PARM1);
//char *antipattern = PR_GetStringOfs(prinst, OFS_PARM2);
int bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
char *pattern = PR_GetStringOfs(prinst, OFS_PARM1);
char *antipattern = PR_GetStringOfs(prinst, OFS_PARM2);
int i;
cvar_group_t *grp;
cvar_t *var;
extern cvar_group_t *cvar_groups;
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
if (strbuflist[bufno].prinst != prinst)
return;
Con_Printf("PF_buf_cvarlist: stub\n");
//obliterate any and all existing data.
for (i = 0; i < strbuflist[bufno].used; i++)
Z_Free(strbuflist[bufno].strings[i]);
Z_Free(strbuflist[bufno].strings);
strbuflist[bufno].used = strbuflist[bufno].allocated = 0;
//ignore name2, no point listing it twice.
for (grp=cvar_groups ; grp ; grp=grp->next)
for (var=grp->cvars ; var ; var=var->next)
{
if (pattern && wildcmp(pattern, var->name))
continue;
if (antipattern && !wildcmp(antipattern, var->name))
continue;
PF_bufstr_add_internal(bufno, var->name, true);
}
}
//directly reads a file into a stringbuffer
void QCBUILTIN PF_buf_loadfile (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *fname = PR_GetStringOfs(prinst, OFS_PARM0);
int bufno = G_FLOAT(OFS_PARM1)-BUFSTRBASE;
vfsfile_t *file;
char line[8192];
char *fallback;
G_FLOAT(OFS_RETURN) = 0;
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
if (strbuflist[bufno].prinst != prinst)
return;
if (!QC_FixFileName(fname, &fname, &fallback))
{
Con_Printf("qcfopen: Access denied: %s\n", fname);
return;
}
file = FS_OpenVFS(fname, "rb", FS_GAME);
if (!file && fallback)
file = FS_OpenVFS(fallback, "rb", FS_GAME);
if (!file)
return;
while(VFS_GETS(file, line, sizeof(line)))
{
PF_bufstr_add_internal(bufno, line, true);
}
VFS_CLOSE(file);
G_FLOAT(OFS_RETURN) = 1;
}
void QCBUILTIN PF_buf_writefile (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
unsigned int fnum = G_FLOAT(OFS_PARM0) - FIRST_QC_FILE_INDEX;
int bufno = G_FLOAT(OFS_PARM1)-BUFSTRBASE;
char **strings;
int idx, midx;
G_FLOAT(OFS_RETURN) = 0;
if ((unsigned int)bufno >= NUMSTRINGBUFS)
return;
if (strbuflist[bufno].prinst != prinst)
return;
if (fnum < 0 || fnum >= MAX_QC_FILES)
return;
if (pf_fopen_files[fnum].prinst != prinst)
return;
if (prinst->callargc >= 3)
idx = G_FLOAT(OFS_PARM2);
else
idx = 0;
if (prinst->callargc >= 4)
midx = idx + G_FLOAT(OFS_PARM3);
else
midx = strbuflist[bufno].used - idx;
idx = bound(0, idx, strbuflist[bufno].used);
midx = min(midx, strbuflist[bufno].used);
for(strings = strbuflist[bufno].strings; idx < midx; idx++)
{
PF_fwrite (prinst, fnum, strings[idx], strlen(strings[idx]));
}
G_FLOAT(OFS_RETURN) = 1;
}
//515's String functions
@ -2866,7 +3133,7 @@ void QCBUILTIN PF_crc16 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
G_FLOAT(OFS_RETURN) = QCRC_Block(str, len);
}
int SHA1(char *digest, int maxdigestsize, char *string);
int SHA1(char *digest, int maxdigestsize, char *string, int stringlen);
void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *hashtype = PR_GetStringOfs(prinst, OFS_PARM0);
@ -2882,7 +3149,7 @@ void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
}
else if (!strcmp(hashtype, "SHA1"))
{
digestsize = SHA1(digest, sizeof(digest), str);
digestsize = SHA1(digest, sizeof(digest), str, strlen(str));
}
else if (!strcmp(hashtype, "CRC16"))
{
@ -4300,7 +4567,7 @@ lh_extension_t QSG_Extensions[] = {
{"FTE_PEXT_MODELDBL"}, //max of 512 models
{"FTE_PEXT_ENTITYDBL"}, //max of 1024 ents
{"FTE_PEXT_ENTITYDBL2"}, //max of 2048 ents
{"FTE_PEXT_ORIGINDBL"}, //-8k to +8k map size.
{"FTE_PEXT_FLOATCOORDS"},
{"FTE_PEXT_VWEAP"},
{"FTE_PEXT_Q2BSP"}, //supports q2 maps. No bugs are apparent.
{"FTE_PEXT_Q3BSP"}, //quake3 bsp support. dp probably has an equivelent, but this is queryable per client.

View File

@ -286,7 +286,6 @@ void QCBUILTIN PF_strconv (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
void QCBUILTIN PF_infoadd (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_infoget (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strncmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strcasecmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strncasecmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strpad (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -378,11 +377,14 @@ void QCBUILTIN PF_bufstr_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
void QCBUILTIN PF_bufstr_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_bufstr_free (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_buf_cvarlist (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_buf_loadfile (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_buf_writefile (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_hash_createtab (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_hash_destroytab (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_hash_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_hash_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_hash_getcb (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_hash_delete (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_hash_getkey (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -528,6 +530,7 @@ typedef enum
VF_AFOV = 203, //aproximate fov (match what the engine would normally use for the fov cvar). p0=fov, p1=zoom
VF_SCREENVSIZE = 204,
VF_SCREENPSIZE = 205,
VF_VIEWENTITY = 206,
} viewflags;
/*FIXME: this should be changed*/
@ -540,7 +543,7 @@ typedef enum
#define CSQCRF_USEAXIS 16 //use v_forward/v_right/v_up as an axis/matrix - predraw is needed to use this properly
#define CSQCRF_NOSHADOW 32 //don't cast shadows upon other entities (can still be self shadowing, if the engine wishes, and not additive)
#define CSQCRF_FRAMETIMESARESTARTTIMES 64 //EXT_CSQC_1: frame times should be read as (time-frametime).
#define CSQCRF_NOAUTOADD 128 //EXT_CSQC_1: don't automatically add after predraw was called
#define CSQCRF_REMOVED 128 //was stupid
/*only read+append+write are standard frik_file*/
#define FRIK_FILE_READ 0 /*read-only*/

View File

@ -852,7 +852,7 @@ enum {
==========================================================
*/
#define MAX_CLIENTS 32//255 /*max 255, min 32*/
#define MAX_CLIENTS 255 /*max 255, min 32*/
#define QWMAX_CLIENTS 32 /*QW's standard max. clients might have issues above this value*/
#define NQMAX_CLIENTS 16 /*NQ's standard max. clients might have issues above this value*/

View File

@ -89,7 +89,8 @@ dllhandle_t *QVM_LoadDLL(const char *name, qboolean binroot, void **vmMain, sys_
hVM=NULL;
{
char fname[MAX_OSPATH];
char *gpath;
char gpath[MAX_OSPATH];
void *iterator;
if (binroot)
{
@ -101,13 +102,9 @@ dllhandle_t *QVM_LoadDLL(const char *name, qboolean binroot, void **vmMain, sys_
else
{
// run through the search paths
gpath = NULL;
while (!hVM)
iterator = NULL;
while (!hVM && COM_IteratePaths(&iterator, gpath, sizeof(gpath)))
{
gpath = COM_NextPath (gpath);
if (!gpath)
break; // couldn't find one anywhere
if (!hVM)
{
snprintf (fname, sizeof(fname), "%s/%s", gpath, dllname_arch);

View File

@ -179,14 +179,14 @@ memset(&finalcount, 0, 8);
}
int SHA1(char *digest, int maxdigestsize, char *string)
int SHA1(char *digest, int maxdigestsize, char *string, int stringlen)
{
SHA1_CTX context;
if (maxdigestsize < DIGEST_SIZE)
return 0;
SHA1Init(&context);
SHA1Update(&context, (unsigned char*) string, strlen(string));
SHA1Update(&context, (unsigned char*) string, stringlen);
SHA1Final(digest, &context);
return DIGEST_SIZE;

View File

@ -44,6 +44,8 @@ NORETURN void VARGS Sys_Error (const char *error, ...) LIKEPRINTF(1);
void VARGS Sys_Printf (char *fmt, ...) LIKEPRINTF(1);
// send text to the console
void Sys_Warn (char *fmt, ...) LIKEPRINTF(1);
//like Sys_Printf. dunno why there needs to be two of em.
void Sys_Quit (void);
void Sys_RecentServer(char *command, char *target, char *title, char *desc);

View File

@ -69,19 +69,24 @@ qboolean Plug_CenterPrintMessage(char *buffer, int clientnum);
qboolean Plug_ChatMessage(char *buffer, int talkernum, int tpflags);
void Plug_Command_f(void);
int Plug_ConnectionlessClientPacket(char *buffer, int size);
qboolean Plug_ConsoleLink(char *text, char *info);
void Plug_DrawReloadImages(void);
void Plug_Initialise(qboolean fromgamedir);
void Plug_Shutdown(qboolean preliminary);
qboolean Plug_Menu_Event(int eventtype, int param);
void Plug_ResChanged(void);
void Plug_SBar(void);
void Plug_SBar(playerview_t *pv);
qboolean Plug_ServerMessage(char *buffer, int messagelevel);
void Plug_Tick(void);
qboolean Plugin_ExecuteString(void);
#endif
#define VM_TOSTRCACHE(a) VMQ3_StringToHandle(VM_POINTER(a))
#define VM_FROMSTRCACHE(a) VMQ3_StringFromHandle(a)
char *VMQ3_StringFromHandle(int handle);
int VMQ3_StringToHandle(char *str);
void VMQ3_FlushStringHandles(void);
#ifdef VM_UI
qboolean UI_Command(void);

View File

@ -118,6 +118,8 @@ void BZ_Free(void *ptr);
#define BZF_Realloc(ptr, size) BZF_ReallocNamed(ptr, size, __FILE__, __LINE__)
#endif
#define Z_StrDup(s) strcpy(Z_Malloc(strlen(s)+1), s)
void *Hunk_Alloc (int size); // returns 0 filled memory
void *Hunk_AllocName (int size, char *name);

View File

@ -345,7 +345,7 @@ static void D3D11BE_ApplyShaderBits(unsigned int bits)
if (delta & (SBITS_BLEND_BITS|SBITS_MASK_BITS))
{
D3D11_BLEND_DESC blend;
D3D11_BLEND_DESC blend = {0};
ID3D11BlendState *newblendstate;
blend.IndependentBlendEnable = FALSE;
blend.AlphaToCoverageEnable = FALSE; //FIXME
@ -354,27 +354,27 @@ static void D3D11BE_ApplyShaderBits(unsigned int bits)
{
switch(bits & SBITS_SRCBLEND_BITS)
{
case SBITS_SRCBLEND_ZERO: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_ZERO; break;
case SBITS_SRCBLEND_ONE: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; break;
case SBITS_SRCBLEND_DST_COLOR: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_COLOR; break;
case SBITS_SRCBLEND_ONE_MINUS_DST_COLOR: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_COLOR; break;
case SBITS_SRCBLEND_SRC_ALPHA: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; break;
case SBITS_SRCBLEND_ONE_MINUS_SRC_ALPHA: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC_ALPHA; break;
case SBITS_SRCBLEND_DST_ALPHA: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_ALPHA; break;
case SBITS_SRCBLEND_ONE_MINUS_DST_ALPHA: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_ALPHA; break;
case SBITS_SRCBLEND_ALPHA_SATURATE: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA_SAT; break;
case SBITS_SRCBLEND_ZERO: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_ZERO; break;
case SBITS_SRCBLEND_ONE: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; break;
case SBITS_SRCBLEND_DST_COLOR: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_COLOR; break;
case SBITS_SRCBLEND_ONE_MINUS_DST_COLOR: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_COLOR; break;
case SBITS_SRCBLEND_SRC_ALPHA: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; break;
case SBITS_SRCBLEND_ONE_MINUS_SRC_ALPHA: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC_ALPHA; break;
case SBITS_SRCBLEND_DST_ALPHA: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_ALPHA; break;
case SBITS_SRCBLEND_ONE_MINUS_DST_ALPHA: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_ALPHA; break;
case SBITS_SRCBLEND_ALPHA_SATURATE: blend.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA_SAT; break;
default: Sys_Error("Bad shader blend src\n"); return;
}
switch(bits & SBITS_DSTBLEND_BITS)
{
case SBITS_DSTBLEND_ZERO: blend.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; break;
case SBITS_DSTBLEND_ONE: blend.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; break;
case SBITS_DSTBLEND_SRC_ALPHA: blend.RenderTarget[0].DestBlend = D3D11_BLEND_SRC_ALPHA; break;
case SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA: blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; break;
case SBITS_DSTBLEND_DST_ALPHA: blend.RenderTarget[0].DestBlend = D3D11_BLEND_DEST_ALPHA; break;
case SBITS_DSTBLEND_ONE_MINUS_DST_ALPHA: blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_DEST_ALPHA; break;
case SBITS_DSTBLEND_SRC_COLOR: blend.RenderTarget[0].DestBlend = D3D11_BLEND_SRC_COLOR; break;
case SBITS_DSTBLEND_ONE_MINUS_SRC_COLOR: blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_COLOR; break;
case SBITS_DSTBLEND_ZERO: blend.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; break;
case SBITS_DSTBLEND_ONE: blend.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; break;
case SBITS_DSTBLEND_SRC_ALPHA: blend.RenderTarget[0].DestBlend = D3D11_BLEND_SRC_ALPHA; break;
case SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA: blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; break;
case SBITS_DSTBLEND_DST_ALPHA: blend.RenderTarget[0].DestBlend = D3D11_BLEND_DEST_ALPHA; break;
case SBITS_DSTBLEND_ONE_MINUS_DST_ALPHA: blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_DEST_ALPHA; break;
case SBITS_DSTBLEND_SRC_COLOR: blend.RenderTarget[0].DestBlend = D3D11_BLEND_SRC_COLOR; break;
case SBITS_DSTBLEND_ONE_MINUS_SRC_COLOR: blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_COLOR; break;
default: Sys_Error("Bad shader blend dst\n"); return;
}
blend.RenderTarget[0].BlendEnable = TRUE;
@ -386,8 +386,8 @@ static void D3D11BE_ApplyShaderBits(unsigned int bits)
blend.RenderTarget[0].BlendEnable = FALSE;
}
blend.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blend.RenderTarget[0].SrcBlendAlpha = blend.RenderTarget[0].SrcBlend;
blend.RenderTarget[0].DestBlendAlpha = blend.RenderTarget[0].DestBlend;
blend.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;//blend.RenderTarget[0].SrcBlend;
blend.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;//blend.RenderTarget[0].DestBlend;
blend.RenderTarget[0].BlendOpAlpha = blend.RenderTarget[0].BlendOp;
if (bits&SBITS_MASK_BITS)
@ -2929,4 +2929,9 @@ void D3D11BE_VBO_Destroy(vboarray_t *vearray)
{
}
void D3D11BE_Scissor(srect_t *rect)
{
//stub
}
#endif

View File

@ -3175,4 +3175,24 @@ void D3D9BE_VBO_Destroy(vboarray_t *vearray)
{
}
void D3D9BE_Scissor(srect_t *srect)
{
RECT rect;
if (srect)
{
rect.left = srect->x;
rect.right = srect->x + srect->width;
rect.top = srect->y;
rect.bottom = srect->y + srect->height;
}
else
{
rect.left = 0;
rect.right = vid.pixelwidth;
rect.top = 0;
rect.bottom = vid.pixelheight;
}
IDirect3DDevice9_SetScissorRect(pD3DDev9, &rect);
}
#endif

View File

@ -1299,6 +1299,7 @@ rendererinfo_t d3d9rendererinfo =
D3D9BE_UploadAllLightmaps,
D3D9BE_SelectEntity,
D3D9BE_SelectDLight,
D3D9BE_Scissor,
D3D9BE_LightCullModel,
D3D9BE_VBO_Begin,

View File

@ -443,6 +443,7 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
if (!D3D11AppActivate(!(fActive == WA_INACTIVE), fMinimized))
break;//so, urm, tell me microsoft, what changed?
if (modestate == MS_FULLDIB)
ShowWindow(mainwindow, SW_SHOWNORMAL);
if (ActiveApp && modestate == MS_FULLSCREEN)
@ -788,14 +789,7 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette)
mouseactive = false;
}
{
void GLV_Gamma_Callback(struct cvar_s *var, char *oldvalue);
Cvar_Hook(&v_gamma, GLV_Gamma_Callback);
Cvar_Hook(&v_contrast, GLV_Gamma_Callback);
Cvar_Hook(&v_brightness, GLV_Gamma_Callback);
Cvar_ForceCallback(&v_gamma);
}
Cvar_ForceCallback(&v_gamma);
return true;
}
@ -1375,6 +1369,7 @@ rendererinfo_t d3d11rendererinfo =
D3D11BE_UploadAllLightmaps,
D3D11BE_SelectEntity,
D3D11BE_SelectDLight,
D3D11BE_Scissor,
D3D11BE_LightCullModel,
D3D11BE_VBO_Begin,

View File

@ -23,7 +23,7 @@
>
<Tool
Name="VCNMakeTool"
BuildCommandLine="cd $(InputDir)\.. &amp;&amp; make droid-dbg PATH=C:\Cygwin\bin\ DROID_SDK_PATH=/cygdrive/c/Games/tools/android-sdk DROID_NDK_PATH=/cygdrive/c/Games/tools/android-ndk-r7 ANT=/cygdrive/c/Games/tools/apache-ant-1.8.2/bin/ant JAVATOOL=&quot;/cygdrive/c/Program\ Files/Java/jdk1.7.0_02/bin/&quot; -j8 DROID_ARCH=&quot;armeabi x86&quot;"
BuildCommandLine="cd $(InputDir)\.. &amp;&amp; make droid-dbg ANDROID_HOME=C:/Games/tools/android-sdk ANDROID_NDK_ROOT=C:/Games/tools/android-ndk-r8e ANT=C:/Games/tools/apache-ant-1.8.2/bin/ant JAVATOOL=&quot;C:/Program\ Files/Java/jdk1.7.0_02/bin/&quot; -j8 DROID_ARCH=&quot;armeabi x86&quot;"
ReBuildCommandLine=""
CleanCommandLine="cd $(InputDir)\..\.. &amp;&amp; make clean -j8"
Output=""
@ -72,6 +72,10 @@
RelativePath="..\droid\src\com\fteqw\FTEDroidEngine.java"
>
</File>
<File
RelativePath="..\gl\gl_viddroid.c"
>
</File>
<File
RelativePath="..\client\in_generic.c"
>

View File

@ -37,6 +37,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jabbercl", "..\..\plugins\j
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fs_mpq", "..\..\plugins\mpq\fs_mpq.vcproj", "{72269FEE-293D-40BC-A7AE-E429F4496869}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpserver", "..\http\httpserver.vcproj", "{E6BAD203-4704-4860-9C38-D4702E9CAD7D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
D3DDebug|Win32 = D3DDebug|Win32
@ -85,7 +87,6 @@ Global
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|x64.ActiveCfg = GLDebug|x64
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|x64.Build.0 = GLDebug|x64
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|Win32.ActiveCfg = GLRelease|Win32
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|Win32.Build.0 = GLRelease|Win32
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|x64.ActiveCfg = GLRelease|x64
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|x64.Build.0 = GLRelease|x64
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|Win32.ActiveCfg = MDebug|Win32
@ -244,9 +245,9 @@ Global
{2866F783-6B44-4655-A38D-D53874037454}.Debug|Win32.Build.0 = Debug|Win32
{2866F783-6B44-4655-A38D-D53874037454}.Debug|x64.ActiveCfg = Release|Win32
{2866F783-6B44-4655-A38D-D53874037454}.GLDebug|Win32.ActiveCfg = Debug|Win32
{2866F783-6B44-4655-A38D-D53874037454}.GLDebug|Win32.Build.0 = Debug|Win32
{2866F783-6B44-4655-A38D-D53874037454}.GLDebug|x64.ActiveCfg = Debug|Win32
{2866F783-6B44-4655-A38D-D53874037454}.GLRelease|Win32.ActiveCfg = Release|Win32
{2866F783-6B44-4655-A38D-D53874037454}.GLRelease|Win32.Build.0 = Release|Win32
{2866F783-6B44-4655-A38D-D53874037454}.GLRelease|x64.ActiveCfg = Release|Win32
{2866F783-6B44-4655-A38D-D53874037454}.MDebug|Win32.ActiveCfg = Debug|Win32
{2866F783-6B44-4655-A38D-D53874037454}.MDebug|Win32.Build.0 = Debug|Win32
@ -513,6 +514,42 @@ Global
{72269FEE-293D-40BC-A7AE-E429F4496869}.Release|Win32.ActiveCfg = Release|Win32
{72269FEE-293D-40BC-A7AE-E429F4496869}.Release|Win32.Build.0 = Release|Win32
{72269FEE-293D-40BC-A7AE-E429F4496869}.Release|x64.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.D3DDebug|Win32.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.D3DDebug|Win32.Build.0 = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.D3DDebug|x64.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.D3DRelease|Win32.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.D3DRelease|Win32.Build.0 = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.D3DRelease|x64.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Debug Dedicated Server|Win32.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Debug Dedicated Server|Win32.Build.0 = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Debug Dedicated Server|x64.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Debug|Win32.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Debug|Win32.Build.0 = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Debug|x64.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.GLDebug|Win32.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.GLDebug|Win32.Build.0 = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.GLDebug|x64.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.GLRelease|Win32.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.GLRelease|Win32.Build.0 = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.GLRelease|x64.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MDebug|Win32.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MDebug|Win32.Build.0 = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MDebug|x64.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MinGLDebug|Win32.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MinGLDebug|Win32.Build.0 = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MinGLDebug|x64.ActiveCfg = Debug|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MinGLRelease|Win32.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MinGLRelease|Win32.Build.0 = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MinGLRelease|x64.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MRelease|Win32.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MRelease|Win32.Build.0 = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.MRelease|x64.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release Dedicated Server|Win32.Build.0 = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release Dedicated Server|x64.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release|Win32.ActiveCfg = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release|Win32.Build.0 = Release|Win32
{E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -17,6 +17,31 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/x-qtv" />
<data android:mimeType="application/x-ftemanifest" />
<data android:scheme="http" android:host="*" android:pathPattern=".*\\.qtv" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\.qtv" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.qtv" />
<data android:scheme="http" android:host="*" android:pathPattern=".*\\.mvd" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\.mvd" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.mvd" />
<data android:scheme="http" android:host="*" android:pathPattern=".*\\.dem" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\.dem" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.dem" />
<data android:scheme="http" android:host="*" android:pathPattern=".*\\.pak" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\.pak" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.pak" />
<data android:scheme="http" android:host="*" android:pathPattern=".*\\.pk3" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\.pk3" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.pk3" />
<data android:scheme="http" android:host="*" android:pathPattern=".*\\.bsp" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\.bsp" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.bsp" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -342,8 +342,11 @@ public class FTEDroidActivity extends Activity
public void onSurfaceChanged(GL10 gl, int width, int height)
{
android.util.Log.i("FTEDroid", "Surface changed, now " + width + " by " + height + ".");
FTEDroidEngine.init(width, height, glesversion, basedir, userdir);
inited = true;
if (glesversion != 0)
{
FTEDroidEngine.init(width, height, glesversion, basedir, userdir);
inited = true;
}
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
@ -706,6 +709,31 @@ public class FTEDroidActivity extends Activity
view.audioResume();
}
@Override
protected void onStart()
{
super.onStart();
final android.content.Intent intent = getIntent();
if (intent != null)
{
final android.net.Uri data = intent.getData();
if (data != null)
{
String myloc;
if (data.getScheme().equals("content"))
{ //wtf.
Cursor cursor = this.getContentResolver().query(data, null, null, null, null);
cursor.moveToFirst();
myloc = cursor.getString(0);
cursor.close();
}
else
myloc = data.toString();
FTEDroidEngine.openfile(myloc);
}
}
}
@Override
protected void onStop()

View File

@ -4,6 +4,7 @@ public class FTEDroidEngine
{
public static native void init(int w, int h, int gles2, String apkpath, String usrpath); /* init/reinit */
public static native int frame(float ax, float ay, float az);
public static native int openfile(String filename);
public static native int getvibrateduration(); //in ms
public static native void keypress(int down, int qkey, int unicode);
public static native void motion(int act, int pointerid, float x, float y, float size);

View File

@ -1536,9 +1536,7 @@ void GL_GenerateNormals(float *orgs, float *normals, int *indicies, int numtris,
qboolean BE_ShouldDraw(entity_t *e)
{
if (!r_refdef.externalview && (e->externalmodelview & (1<<r_refdef.currentplayernum)))
return false;
if (!Cam_DrawPlayer(r_refdef.currentplayernum, e->keynum-1))
if (!r_refdef.externalview && (e->flags & Q2RF_EXTERNALMODEL))
return false;
return true;
}
@ -1710,14 +1708,14 @@ static void R_DB_Sprite(batch_t *batch)
return;
}
if (e->flags & Q2RF_WEAPONMODEL && r_refdef.currentplayernum >= 0)
if (e->flags & Q2RF_WEAPONMODEL && r_refdef.playerview->viewentity > 0)
{
sprorigin[0] = cl.viewent[r_refdef.currentplayernum].origin[0];
sprorigin[1] = cl.viewent[r_refdef.currentplayernum].origin[1];
sprorigin[2] = cl.viewent[r_refdef.currentplayernum].origin[2];
VectorMA(sprorigin, e->origin[0], cl.viewent[r_refdef.currentplayernum].axis[0], sprorigin);
VectorMA(sprorigin, e->origin[1], cl.viewent[r_refdef.currentplayernum].axis[1], sprorigin);
VectorMA(sprorigin, e->origin[2], cl.viewent[r_refdef.currentplayernum].axis[2], sprorigin);
sprorigin[0] = r_refdef.playerview->viewent.origin[0];
sprorigin[1] = r_refdef.playerview->viewent.origin[1];
sprorigin[2] = r_refdef.playerview->viewent.origin[2];
VectorMA(sprorigin, e->origin[0], r_refdef.playerview->viewent.axis[0], sprorigin);
VectorMA(sprorigin, e->origin[1], r_refdef.playerview->viewent.axis[1], sprorigin);
VectorMA(sprorigin, e->origin[2], r_refdef.playerview->viewent.axis[2], sprorigin);
VectorMA(sprorigin, 12, vpn, sprorigin);
batch->flags |= BEF_FORCENODEPTH;
@ -1748,11 +1746,11 @@ static void R_DB_Sprite(batch_t *batch)
{
case SPR_ORIENTED:
// bullet marks on walls
if (e->flags & Q2RF_WEAPONMODEL && r_refdef.currentplayernum >= 0)
if ((e->flags & Q2RF_WEAPONMODEL) && r_refdef.playerview->viewentity > 0)
{
vec3_t ea[3];
AngleVectors (e->angles, ea[0], ea[1], ea[2]);
Matrix3_Multiply(ea, cl.viewent[r_refdef.currentplayernum].axis, spraxis);
Matrix3_Multiply(ea, r_refdef.playerview->viewent.axis, spraxis);
}
else
AngleVectors (e->angles, spraxis[0], spraxis[1], spraxis[2]);

View File

@ -416,7 +416,7 @@ void GL_LazyBind(int tmu, int target, texid_t texnum)
#endif
{
if (shaderstate.curtexturetype[tmu])
qglBindTexture (shaderstate.curtexturetype[tmu], texnum.num);
qglBindTexture (shaderstate.curtexturetype[tmu], 0);
if (gl_config.nofixedfunc)
{
shaderstate.curtexturetype[tmu] = target;
@ -945,7 +945,7 @@ void R_IBrokeTheArrays(void)
void GLBE_SetupForShadowMap(texid_t shadowmaptex, int texwidth, int texheight, float shadowscale)
{
shaderstate.lightshadowmapinfo[0] = 1.0/texwidth;
shaderstate.lightshadowmapinfo[1] = 1.0/texwidth;
shaderstate.lightshadowmapinfo[1] = 1.0/texheight;
shaderstate.lightshadowmapinfo[2] = 1.0;
shaderstate.lightshadowmapinfo[3] = shadowscale;
@ -3270,7 +3270,7 @@ static qboolean GLBE_RegisterLightShader(int mode)
void GLBE_SelectDLight(dlight_t *dl, vec3_t colour)
{
float view[16], proj[16];
float view[16];
int lmode;
extern cvar_t gl_specular;
extern cvar_t r_shadow_shadowmapping;
@ -3279,13 +3279,14 @@ void GLBE_SelectDLight(dlight_t *dl, vec3_t colour)
float nearplane = 4;
if (dl->fov)
{
float proj[16];
Matrix4x4_CM_Projection_Far(proj, dl->fov, dl->fov, nearplane, dl->radius);
Matrix4x4_CM_ModelViewMatrixFromAxis(view, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin);
Matrix4_Multiply(proj, view, shaderstate.lightprojmatrix);
}
else
{
Matrix4x4_CM_Projection_Far(proj, 90, 90, nearplane, dl->radius);
// Matrix4x4_CM_Projection_Far(proj, 90, 90, nearplane, dl->radius);
Matrix4x4_CM_ModelViewMatrixFromAxis(shaderstate.lightprojmatrix, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin);
}
@ -3315,6 +3316,31 @@ void GLBE_SelectDLight(dlight_t *dl, vec3_t colour)
shaderstate.lightmode = lmode;
}
void GLBE_Scissor(srect_t *rect)
{
if (rect)
{
qglScissor(
floor(r_refdef.pxrect.x + rect->x*r_refdef.pxrect.width),
floor((r_refdef.pxrect.y + rect->y*r_refdef.pxrect.height) - r_refdef.pxrect.height),
ceil(rect->width * r_refdef.pxrect.width),
ceil(rect->height * r_refdef.pxrect.height));
qglEnable(GL_SCISSOR_TEST);
if (qglDepthBoundsEXT)
{
qglDepthBoundsEXT(rect->dmin, rect->dmax);
qglEnable(GL_DEPTH_BOUNDS_TEST_EXT);
}
}
else
{
qglDisable(GL_SCISSOR_TEST);
if (qglDepthBoundsEXT)
qglDisable(GL_DEPTH_BOUNDS_TEST_EXT);
}
}
void GLBE_PushOffsetShadow(qboolean pushdepth)
{
extern cvar_t r_polygonoffset_stencil_offset, r_polygonoffset_stencil_factor;

View File

@ -293,7 +293,7 @@ void GL_Mipcap_Callback (struct cvar_s *var, char *oldvalue)
void GL_Texturemode_Apply(GLenum targ, unsigned int flags)
{
int mag;
if (flags & IF_2D)
if (flags & IF_UIPIC)
{
qglTexParameteri(targ, GL_TEXTURE_MIN_FILTER, gl_filter_max_2d);
if (flags & IF_NEAREST)
@ -353,7 +353,7 @@ void GL_Texturemode_Callback (struct cvar_s *var, char *oldvalue)
// change all the existing mipmap texture objects
for (glt=gltextures ; glt ; glt=glt->next)
{
if (!(glt->flags & IF_2D))
if (!(glt->flags & IF_UIPIC))
{
if (glt->flags & IF_CUBEMAP)
targ = GL_TEXTURE_CUBE_MAP_ARB;
@ -392,7 +392,7 @@ void GL_Texturemode2d_Callback (struct cvar_s *var, char *oldvalue)
// change all the existing mipmap texture objects
for (glt=gltextures ; glt ; glt=glt->next)
{
if (glt->flags & IF_2D)
if (glt->flags & IF_UIPIC)
{
GL_MTBind(0, GL_TEXTURE_2D, glt->texnum);
GL_Texturemode_Apply(GL_TEXTURE_2D, glt->flags);

View File

@ -26,7 +26,7 @@ void Font_EndString(struct font_s *font);
int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int maxlines, conchar_t **starts, conchar_t **ends);
struct font_s *font_conchar;
struct font_s *font_tiny;
extern int r2d_be_flags;
extern unsigned int r2d_be_flags;
#ifdef AVAIL_FREETYPE
#include <ft2build.h>
@ -262,7 +262,7 @@ void Font_Init(void)
for (i = 0; i < FONTPLANES; i++)
{
TEXASSIGN(fontplanes.texnum[i], R_AllocNewTexture("***fontplane***", PLANEWIDTH, PLANEHEIGHT, IF_2D|IF_NEAREST|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA));
TEXASSIGN(fontplanes.texnum[i], R_AllocNewTexture("***fontplane***", PLANEWIDTH, PLANEHEIGHT, IF_UIPIC|IF_NEAREST|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA));
}
fontplanes.shader = R_RegisterShader("ftefont",
@ -302,7 +302,7 @@ static void Font_Flush(void)
return;
if (fontplanes.planechanged)
{
R_Upload(fontplanes.texnum[fontplanes.activeplane], NULL, TF_RGBA32, (void*)fontplanes.plane, NULL, PLANEWIDTH, PLANEHEIGHT, IF_2D|IF_NEAREST|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA);
R_Upload(fontplanes.texnum[fontplanes.activeplane], NULL, TF_RGBA32, (void*)fontplanes.plane, NULL, PLANEWIDTH, PLANEHEIGHT, IF_UIPIC|IF_NEAREST|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA);
fontplanes.planechanged = false;
}
@ -368,7 +368,7 @@ void Font_FlushPlane(void)
if (fontplanes.planechanged)
{
R_Upload(fontplanes.texnum[fontplanes.activeplane], NULL, TF_RGBA32, (void*)fontplanes.plane, NULL, PLANEWIDTH, PLANEHEIGHT, IF_2D|IF_NEAREST|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA);
R_Upload(fontplanes.texnum[fontplanes.activeplane], NULL, TF_RGBA32, (void*)fontplanes.plane, NULL, PLANEWIDTH, PLANEHEIGHT, IF_UIPIC|IF_NEAREST|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA);
fontplanes.planechanged = false;
}
@ -759,15 +759,15 @@ static texid_t Font_LoadReplacementConchars(void)
{
texid_t tex;
//q1 replacement
tex = R_LoadReplacementTexture("gfx/conchars.lmp", NULL, IF_2D|IF_NOMIPMAP|IF_NOGAMMA);
tex = R_LoadReplacementTexture("gfx/conchars.lmp", NULL, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
if (TEXVALID(tex))
return tex;
//q2
tex = R_LoadHiResTexture("pics/conchars.pcx", NULL, IF_2D|IF_NOMIPMAP|IF_NOGAMMA);
tex = R_LoadHiResTexture("pics/conchars.pcx", NULL, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
if (TEXVALID(tex))
return tex;
//q3
tex = R_LoadHiResTexture("gfx/2d/bigchars.tga", NULL, IF_2D|IF_NOMIPMAP|IF_NOGAMMA);
tex = R_LoadHiResTexture("gfx/2d/bigchars.tga", NULL, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
if (TEXVALID(tex))
return tex;
return r_nulltex;
@ -790,7 +790,7 @@ static texid_t Font_LoadQuakeConchars(void)
if (lump[i] == 0)
lump[i] = 255; // proper transparent color
return R_LoadTexture8("charset", 128, 128, (void*)lump, IF_2D|IF_NOMIPMAP|IF_NOGAMMA, 1);
return R_LoadTexture8("charset", 128, 128, (void*)lump, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, 1);
}
return r_nulltex;
}
@ -876,7 +876,7 @@ static texid_t Font_LoadHexen2Conchars(qboolean iso88591)
for (i=0 ; i<128*128 ; i++)
if (outbuf[i] == 0)
outbuf[i] = 255; // proper transparent color
tex = R_LoadTexture8 (iso88591?"gfx/menu/8859-1.lmp":"charset", 128, 128, outbuf, IF_2D|IF_NOMIPMAP|IF_NOGAMMA, 1);
tex = R_LoadTexture8 (iso88591?"gfx/menu/8859-1.lmp":"charset", 128, 128, outbuf, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, 1);
Z_Free(outbuf);
return tex;
}
@ -902,7 +902,7 @@ static texid_t Font_LoadFallbackConchars(void)
lump[i*4+1] = 255;
lump[i*4+2] = 255;
}
tex = R_LoadTexture32("charset", width, height, (void*)lump, IF_2D|IF_NOMIPMAP|IF_NOGAMMA);
tex = R_LoadTexture32("charset", width, height, (void*)lump, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA);
BZ_Free(lump);
return tex;
}
@ -1061,7 +1061,7 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename)
for (x = 0; x < 128; x++)
img[x + y*PLANEWIDTH] = w[x + y*128]?d_8to24rgbtable[w[x + y*128]]:0;
f->singletexture = R_LoadTexture(fontfilename,PLANEWIDTH,PLANEWIDTH,TF_RGBA32,img,IF_2D|IF_NOPICMIP|IF_NOMIPMAP);
f->singletexture = R_LoadTexture(fontfilename,PLANEWIDTH,PLANEWIDTH,TF_RGBA32,img,IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP);
Z_Free(img);
for (i = 0x00; i <= 0xff; i++)
@ -1123,7 +1123,7 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename)
{
//default to only map the ascii-compatible chars from the quake font.
if (*fontfilename)
f->singletexture = R_LoadHiResTexture(fontfilename, "fonts", IF_2D|IF_NOMIPMAP);
f->singletexture = R_LoadHiResTexture(fontfilename, "fonts", IF_UIPIC|IF_NOMIPMAP);
for ( ; i < 32; i++)
{
@ -1396,6 +1396,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
int Font_LineWidth(conchar_t *start, conchar_t *end)
{
//fixme: does this do the right thing with tabs?
int x = 0;
struct font_s *font = curfont;
for (; start < end; start++)
@ -1404,6 +1405,16 @@ int Font_LineWidth(conchar_t *start, conchar_t *end)
}
return x;
}
float Font_LineScaleWidth(conchar_t *start, conchar_t *end)
{
int x = 0;
struct font_s *font = curfont;
for (; start < end; start++)
{
x = Font_CharEndCoord(font, x, *start);
}
return x * curfont_scale[0];
}
void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end)
{
int lx = 0;

View File

@ -122,7 +122,7 @@ void R_NetGraph (void)
Draw_FunString(8, y, st);
y += 8;
R_Upload(netgraphtexture, "***netgraph***", TF_RGBA32, ngraph_pixels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_2D|IF_NOMIPMAP|IF_NOPICMIP);
R_Upload(netgraphtexture, "***netgraph***", TF_RGBA32, ngraph_pixels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP);
x=8;
R2D_Image(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1, netgraphshader);
}
@ -163,14 +163,14 @@ void R_FrameTimeGraph (int frametime)
Draw_FunString(8, y, st);
y += 8;
R_Upload(netgraphtexture, "***netgraph***", TF_RGBA32, ngraph_pixels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_2D|IF_NOMIPMAP|IF_NOPICMIP);
R_Upload(netgraphtexture, "***netgraph***", TF_RGBA32, ngraph_pixels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP);
x=8;
R2D_Image(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1, netgraphshader);
}
void R_NetgraphInit(void)
{
TEXASSIGN(netgraphtexture, R_AllocNewTexture("***netgraph***", NET_TIMINGS, NET_GRAPHHEIGHT, IF_2D|IF_NOMIPMAP));
TEXASSIGN(netgraphtexture, R_AllocNewTexture("***netgraph***", NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP));
netgraphshader = R_RegisterShader("netgraph",
"{\n"
"program default2d\n"

View File

@ -294,9 +294,9 @@ void R_RenderDlights (void)
if (l->flags & LFLAG_FLASHBLEND)
{
//dlights emitting from the local player are not visible as flashblends
if (l->key == cl.playernum[r_refdef.currentplayernum]+1)
if (l->key == r_refdef.playerview->viewentity)
continue; //was a glow
if (l->key == -(cl.playernum[r_refdef.currentplayernum]+1))
if (l->key == -(r_refdef.playerview->viewentity))
continue; //was a muzzleflash
}

View File

@ -230,9 +230,9 @@ void GL_SetupSceneProcessingTextures (void)
void R_RotateForEntity (float *m, float *modelview, const entity_t *e, const model_t *mod)
{
if (e->flags & Q2RF_WEAPONMODEL && r_refdef.currentplayernum>=0)
if ((e->flags & Q2RF_WEAPONMODEL) && r_refdef.playerview->viewentity > 0)
{
entity_t *view = &cl.viewent[r_refdef.currentplayernum];
entity_t *view = &r_refdef.playerview->viewent;
float em[16];
float vm[16];
@ -382,9 +382,9 @@ void R_SetupGL (float stereooffset)
//
// set up viewpoint
//
x = r_refdef.vrect.x * vid.pixelwidth/(int)vid.width;
x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * vid.pixelwidth/(int)vid.width;
y = (vid.height-r_refdef.vrect.y) * vid.pixelheight/(int)vid.height;
x = r_refdef.vrect.x * (int)vid.pixelwidth/(int)vid.width;
x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * (int)vid.pixelwidth/(int)vid.width;
y = (vid.height-r_refdef.vrect.y) * (int)vid.pixelheight/(int)vid.height;
y2 = ((int)vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * (int)vid.pixelheight/(int)vid.height;
// fudge around because of frac screen scale
@ -1009,7 +1009,7 @@ void R_Clear (void)
/*tbh, this entire function should be in the backend*/
GL_ForceDepthWritable();
{
if (r_clear.ival && !r_secondaryview && !r_refdef.currentplayernum && !(r_refdef.flags & Q2RDF_NOWORLDMODEL))
if (r_clear.ival && r_refdef.grect.x == 0 && r_refdef.grect.y == 0 && r_refdef.grect.width == vid.width && r_refdef.grect.height == vid.height && !(r_refdef.flags & Q2RDF_NOWORLDMODEL))
{
qglClearColor(1, 0, 0, 0);
qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -1195,12 +1195,12 @@ qboolean R_RenderScene_Cubemap(void)
facemask |= 1<<5; /*back view*/
}
//fixme: should already have the vrect somewhere.
SCR_VRectForPlayer(&vrect, r_refdef.currentplayernum);
prect.x = (vrect.x * vid.pixelwidth)/vid.width;
prect.width = (vrect.width * vid.pixelwidth)/vid.width;
prect.y = (vrect.y * vid.pixelheight)/vid.height;
prect.height = (vrect.height * vid.pixelheight)/vid.height;
vrect = r_refdef.vrect;
prect = r_refdef.pxrect;
// prect.x = (vrect.x * vid.pixelwidth)/vid.width;
// prect.width = (vrect.width * vid.pixelwidth)/vid.width;
// prect.y = (vrect.y * vid.pixelheight)/vid.height;
// prect.height = (vrect.height * vid.pixelheight)/vid.height;
if (r_config.texture_non_power_of_two)
{

View File

@ -137,12 +137,6 @@ void GLSCR_UpdateScreen (void)
RSpeedEnd(RSPEED_TOTALREFRESH);
return;
}
//
// determine size of refresh window
//
if (vid.recalc_refdef)
SCR_CalcRefdef ();
//
// do 3D refresh drawing, and then update the screen
@ -191,9 +185,7 @@ void GLSCR_UpdateScreen (void)
scr_con_forcedraw = true;
nohud = true;
}
else if (!nohud)
SCR_TileClear ();
}
SCR_DrawTwoDimensional(uimenu, nohud);

View File

@ -639,7 +639,12 @@ static int Shader_SetImageFlags(shader_t *shader, shaderpass_t *pass, char **nam
if (!Q_strnicmp(*name, "$3d:", 4))
{
*name+=4;
flags|= IF_3DMAP;
flags = (flags&~IF_TEXTYPE) | IF_3DMAP;
}
else if (!Q_strnicmp(*name, "$cube:", 6))
{
*name+=6;
flags = (flags&~IF_TEXTYPE) | IF_CUBEMAP;
}
else if (!Q_strnicmp(*name, "$nearest:", 9))
{
@ -2253,10 +2258,18 @@ static void Shaderpass_Map (shader_t *shader, shaderpass_t *pass, char **ptr)
flags = Shader_SetImageFlags (shader, pass, &token);
if (!Shaderpass_MapGen(shader, pass, token))
{
if (flags & IF_3DMAP)
pass->texgen = T_GEN_3DMAP;
else
switch((flags & IF_TEXTYPE) >> IF_TEXTYPESHIFT)
{
case 0:
pass->texgen = T_GEN_SINGLEMAP;
break;
case 1:
pass->texgen = T_GEN_3DMAP;
break;
default:
pass->texgen = T_GEN_CUBEMAP;
break;
}
pass->tcgen = TC_GEN_BASE;
pass->anim_frames[0] = Shader_FindImage (token, flags);
@ -2285,7 +2298,7 @@ static void Shaderpass_AnimMap (shader_t *shader, shaderpass_t *pass, char **ptr
break;
}
if (pass->anim_numframes < SHADER_ANIM_FRAMES_MAX)
if (pass->anim_numframes < SHADER_MAX_ANIMFRAMES)
{
image = Shader_FindImage (token, flags);
@ -2314,10 +2327,19 @@ static void Shaderpass_ClampMap (shader_t *shader, shaderpass_t *pass, char **pt
{
pass->tcgen = TC_GEN_BASE;
pass->anim_frames[0] = Shader_FindImage (token, flags | IF_CLAMP);
if (flags & IF_3DMAP)
pass->texgen = T_GEN_3DMAP;
else
switch((flags & IF_TEXTYPE) >> IF_TEXTYPESHIFT)
{
case 0:
pass->texgen = T_GEN_SINGLEMAP;
break;
case 1:
pass->texgen = T_GEN_3DMAP;
break;
default:
pass->texgen = T_GEN_CUBEMAP;
break;
}
if (!TEXVALID(pass->anim_frames[0]))
{
@ -4688,7 +4710,7 @@ void Shader_Default2D(char *shortname, shader_t *s, const void *genargs)
"}\n"
);
TEXASSIGN(s->defaulttextures.base, R_LoadHiResTexture(shortname, NULL, IF_2D|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP));
TEXASSIGN(s->defaulttextures.base, R_LoadHiResTexture(shortname, NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP));
if (!TEXVALID(s->defaulttextures.base))
{
unsigned char data[4*4] = {0};

View File

@ -103,8 +103,14 @@ typedef struct {
vbo_t *vbo;
mesh_t **s;
} shadowmeshbatch_t;
typedef struct shadowmesh_s {
qboolean surfonly;
typedef struct shadowmesh_s
{
enum
{
SMT_STENCILVOLUME,
SMT_SHADOWLESS,
SMT_SURFACES
} type;
unsigned int numindicies;
unsigned int maxindicies;
index_t *indicies;
@ -361,7 +367,7 @@ static void SH_CalcShadowBatches(model_t *mod)
}
}
static void SHM_BeginShadowMesh(dlight_t *dl, qboolean surfonly)
static void SHM_BeginShadowMesh(dlight_t *dl, int type)
{
unsigned int i;
unsigned int lb;
@ -404,7 +410,7 @@ static void SHM_BeginShadowMesh(dlight_t *dl, qboolean surfonly)
sh_shmesh->numverts = 0;
sh_shmesh->maxindicies = 0;
sh_shmesh->numindicies = 0;
sh_shmesh->surfonly = surfonly;
sh_shmesh->type = type;
if (!cl.worldmodel->numshadowbatches)
{
@ -622,7 +628,7 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
if ((s*s+t*t+dot*dot) < maxdist)
{
SHM_Shadow_Cache_Surface(surf);
if (sh_shmesh->surfonly)
if (sh_shmesh->type != SMT_STENCILVOLUME)
continue;
//build a list of the edges that are to be drawn.
@ -809,7 +815,7 @@ static void SHM_RecursiveWorldNodeQ2_r (dlight_t *dl, mnode_t *node)
if ((s*s+t*t+dot*dot) < maxdist)
{
SHM_Shadow_Cache_Surface(surf);
if (sh_shmesh->surfonly)
if (sh_shmesh->type != SMT_STENCILVOLUME)
continue;
//build a list of the edges that are to be drawn.
@ -1282,12 +1288,12 @@ static void SHM_ComposeVolume_BruteForce(dlight_t *dl)
}
}
static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvis, unsigned char *vvis, qboolean surfonly)
static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvis, unsigned char *vvis, int type)
{
float *v1, *v2;
vec3_t v3, v4;
if (dl->worldshadowmesh && !dl->rebuildcache)
if (dl->worldshadowmesh && !dl->rebuildcache && dl->worldshadowmesh->type == type)
return dl->worldshadowmesh;
firstedge=0;
@ -1307,14 +1313,14 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
}
else*/
{
SHM_BeginShadowMesh(dl, surfonly);
SHM_BeginShadowMesh(dl, type);
SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
}
break;
#ifdef Q2BSPS
case fg_quake2:
SHM_BeginShadowMesh(dl, surfonly);
SHM_BeginShadowMesh(dl, type);
SHM_MarkLeavesQ2(dl, lvis, vvis);
SHM_RecursiveWorldNodeQ2_r(dl, cl.worldmodel->nodes);
break;
@ -1325,7 +1331,7 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
SHM_BeginShadowMesh(dl, true);
sh_shadowframe++;
SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes);
if (!surfonly)
if (type == SMT_STENCILVOLUME)
SHM_ComposeVolume_BruteForce(dl);
break;
#endif
@ -1334,8 +1340,14 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
}
/*generate edge polys for map types that need it (q1/q2)*/
if (!surfonly)
switch (type)
{
case SMT_SURFACES:
{
}
break;
case SMT_STENCILVOLUME:
SHM_BeginQuads();
while(firstedge)
{
@ -1371,6 +1383,7 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
firstedge = edge[firstedge].next;
}
SHM_End();
break;
}
return SHM_FinishShadowMesh(dl);
@ -1441,16 +1454,9 @@ static qboolean Sh_LeafInView(qbyte *lightvis, qbyte *vvis)
}
#endif
typedef struct
{
float x;
float y;
float width;
float height;
double dmin;
double dmax;
} srect_t;
static void Sh_Scissor (srect_t r)
/*
static void Sh_Scissor (srect_t *r)
{
//float xs = vid.pixelwidth / (float)vid.width, ys = vid.pixelheight / (float)vid.height;
switch(qrenderer)
@ -1464,15 +1470,15 @@ static void Sh_Scissor (srect_t r)
case QR_OPENGL:
#ifdef GLQUAKE
qglScissor(
floor(r_refdef.pxrect.x + r.x*r_refdef.pxrect.width),
floor((r_refdef.pxrect.y + r.y*r_refdef.pxrect.height) - r_refdef.pxrect.height),
ceil(r.width * r_refdef.pxrect.width),
ceil(r.height * r_refdef.pxrect.height));
floor(r_refdef.pxrect.x + r->x*r_refdef.pxrect.width),
floor((r_refdef.pxrect.y + r->y*r_refdef.pxrect.height) - r_refdef.pxrect.height),
ceil(r->width * r_refdef.pxrect.width),
ceil(r->height * r_refdef.pxrect.height));
qglEnable(GL_SCISSOR_TEST);
if (qglDepthBoundsEXT)
{
qglDepthBoundsEXT(r.dmin, r.dmax);
qglDepthBoundsEXT(r->dmin, r->dmax);
qglEnable(GL_DEPTH_BOUNDS_TEST_EXT);
}
#endif
@ -1481,10 +1487,10 @@ static void Sh_Scissor (srect_t r)
#ifdef D3D9QUAKE
{
RECT rect;
rect.left = r.x;
rect.right = r.x + r.width;
rect.top = r.y;
rect.bottom = r.y + r.height;
rect.left = r->x;
rect.right = r->x + r->width;
rect.top = r->y;
rect.bottom = r->y + r->height;
IDirect3DDevice9_SetScissorRect(pD3DDev9, &rect);
}
#endif
@ -1510,7 +1516,7 @@ static void Sh_ScissorOff (void)
break;
}
}
*/
#if 0
static qboolean Sh_ScissorForSphere(vec3_t center, float radius, vrect_t *rect)
{
@ -2014,16 +2020,25 @@ GL_CullFace(0);
BE_SelectEntity(&r_worldentity);
for (tno = 0; tno < smesh->numbatches; tno++)
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL)
GLBE_RenderShadowBuffer(smesh->numverts, smesh->vebo[0], NULL, smesh->numindicies, smesh->vebo[1], NULL);
else
#endif
{
if (!smesh->batches[tno].count)
continue;
tex = cl.worldmodel->shadowbatches[tno].tex;
if (tex->shader->flags & SHADER_NODLIGHT)
continue;
BE_DrawMesh_List(tex->shader, smesh->batches[tno].count, smesh->batches[tno].s, cl.worldmodel->shadowbatches[tno].vbo, &tex->shader->defaulttextures, 0);
//FIXME: should be able to merge batches between textures+lightmaps.
for (tno = 0; tno < smesh->numbatches; tno++)
{
if (!smesh->batches[tno].count)
continue;
tex = cl.worldmodel->shadowbatches[tno].tex;
if (tex->shader->flags & SHADER_NODLIGHT)
continue;
BE_DrawMesh_List(tex->shader, smesh->batches[tno].count, smesh->batches[tno].s, cl.worldmodel->shadowbatches[tno].vbo, &tex->shader->defaulttextures, 0);
}
}
//fixme: this walks through the entity lists up to 6 times per frame.
switch(qrenderer)
{
default:
@ -2075,6 +2090,7 @@ void Sh_GenShadowMap (dlight_t *l, qbyte *lvis)
float oproj[16], oview[16];
shadowmesh_t *smesh;
int isspot = (l->fov != 0);
extern cvar_t temp1;
if (!TEXVALID(shadowmap[isspot]))
{
@ -2085,7 +2101,7 @@ void Sh_GenShadowMap (dlight_t *l, qbyte *lvis)
#ifdef DBG_COLOURNOTDEPTH
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, smsize, smsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
#else
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32_ARB, SHADOWMAP_SIZE, SHADOWMAP_SIZE, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_ARB, SHADOWMAP_SIZE, SHADOWMAP_SIZE, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
#endif
}
else
@ -2095,7 +2111,7 @@ void Sh_GenShadowMap (dlight_t *l, qbyte *lvis)
#ifdef DBG_COLOURNOTDEPTH
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, smsize*3, smsize*2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
#else
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32_ARB, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_ARB, SHADOWMAP_SIZE*3, SHADOWMAP_SIZE*2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
#endif
}
@ -2117,9 +2133,11 @@ void Sh_GenShadowMap (dlight_t *l, qbyte *lvis)
smesh = SHM_BuildShadowMesh(l, lvis, NULL, true);
smsize = bound(16, temp1.ival, SHADOWMAP_SIZE);
/*set framebuffer*/
GL_BeginRenderBuffer_DepthOnly(shadowmap[isspot]);
GLBE_SetupForShadowMap(shadowmap[isspot], isspot?smsize:smsize*3, isspot?smsize:smsize*2, smsize / (float)SHADOWMAP_SIZE);
GLBE_SetupForShadowMap(shadowmap[isspot], isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
qglViewport(0, 0, smsize*3, smsize*2);
qglClear (GL_DEPTH_BUFFER_BIT);
@ -2165,8 +2183,6 @@ void Sh_GenShadowMap (dlight_t *l, qbyte *lvis)
memcpy(r_refdef.m_view, oview, sizeof(r_refdef.m_view));
memcpy(r_refdef.m_projection, oproj, sizeof(r_refdef.m_projection));
qglDisable(GL_POLYGON_OFFSET_FILL);
if (!gl_config.nofixedfunc)
{
qglMatrixMode(GL_PROJECTION);
@ -2234,14 +2250,14 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, qbyte *vvis)
else
lvis = NULL;
Sh_ScissorOff();
BE_Scissor(NULL);
Sh_GenShadowMap(l, lvis);
bench.numlights++;
//may as well use scissors
Sh_Scissor(rect);
BE_Scissor(&rect);
BE_SelectEntity(&r_worldentity);
@ -2584,7 +2600,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, qbyte *vvis)
//The backend doesn't maintain scissor state.
//The backend doesn't maintain stencil test state either - it needs to be active for more than just stencils, or disabled. its awkward.
Sh_Scissor(rect);
BE_Scissor(&rect);
switch(qrenderer)
@ -2818,7 +2834,7 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, qbyte *vvis)
}
//should we actually scissor here? there's not really much point I suppose.
Sh_ScissorOff();
BE_Scissor(NULL);
bench.numlights++;
@ -2897,7 +2913,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}
Sh_ScissorOff();
BE_Scissor(NULL);
GLBE_RenderToTexture(r_nulltex, r_nulltex, crepuscular_texture_id, r_nulltex, false);
@ -3101,7 +3117,7 @@ void Sh_DrawLights(qbyte *vis)
}
}
Sh_ScissorOff();
BE_Scissor(NULL);
BE_SelectMode(BEM_STANDARD);

View File

@ -1917,6 +1917,7 @@ rendererinfo_t openglrendererinfo = {
GLBE_UploadAllLightmaps,
GLBE_SelectEntity,
GLBE_SelectDLight,
GLBE_Scissor,
GLBE_LightCullModel,
GLBE_VBO_Begin,

View File

@ -968,8 +968,6 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette)
// fix the leftover Alt from any Alt-Tab or the like that switched us away
ClearAllStates ();
vid.recalc_refdef = 1;
if (vid_desktopgamma.value)
{
HDC hDC = GetDC(GetDesktopWindow());
@ -1416,60 +1414,6 @@ void OblitterateOldGamma(void)
}
}
void GLVID_SetPalette (unsigned char *palette)
{
qbyte *pal;
unsigned r,g,b;
unsigned v;
unsigned short i;
unsigned *table;
extern qbyte gammatable[256];
//
// 8 8 8 encoding
//
if (vid_hardwaregamma.value)
{
// don't built in the gamma table
pal = palette;
table = d_8to24rgbtable;
for (i=0 ; i<256 ; i++)
{
r = pal[0];
g = pal[1];
b = pal[2];
pal += 3;
// v = (255<<24) + (r<<16) + (g<<8) + (b<<0);
// v = (255<<0) + (r<<8) + (g<<16) + (b<<24);
v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
*table++ = v;
}
d_8to24rgbtable[255] &= 0xffffff; // 255 is transparent
}
else
{
//computer has no hardware gamma (poor suckers) increase table accordingly
pal = palette;
table = d_8to24rgbtable;
for (i=0 ; i<256 ; i++)
{
r = gammatable[pal[0]];
g = gammatable[pal[1]];
b = gammatable[pal[2]];
pal += 3;
// v = (255<<24) + (r<<16) + (g<<8) + (b<<0);
// v = (255<<0) + (r<<8) + (g<<16) + (b<<24);
v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
*table++ = v;
}
d_8to24rgbtable[255] &= 0xffffff; // 255 is transparent
}
}
qboolean GLVID_ApplyGammaRamps (unsigned short *ramps)
{
if (ramps)
@ -1888,7 +1832,7 @@ LONG WINAPI GLMainWndProc (
case WM_COPYDATA:
{
COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lParam;
Sys_RunFile(cds->lpData, cds->cbData);
Host_RunFile(cds->lpData, cds->cbData, NULL);
}
break;
case WM_KILLFOCUS:

View File

@ -6,8 +6,7 @@ typedef void (shader_gen_t)(char *name, shader_t*, const void *args);
#define SHADER_PASS_MAX 8
#define SHADER_MAX_TC_MODS 8
#define SHADER_DEFORM_MAX 8
#define SHADER_MAX_ANIMFRAMES 8
#define SHADER_ANIM_FRAMES_MAX 16
#define SHADER_MAX_ANIMFRAMES 16
#define SHADER_PROGPARMS_MAX 16
@ -516,6 +515,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis);
qboolean GLBE_LightCullModel(vec3_t org, model_t *model);
void GLBE_SelectEntity(entity_t *ent);
void GLBE_SelectDLight(dlight_t *dl, vec3_t colour);
void GLBE_Scissor(srect_t *rect);
void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop);
void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth);
void GLBE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize);
@ -542,6 +542,7 @@ void D3D9BE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize);
void D3D9BE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray);
void D3D9BE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray);
void D3D9BE_VBO_Destroy(vboarray_t *vearray);
void D3D9BE_Scissor(srect_t *rect);
qboolean D3D9Shader_CreateProgram (program_t *prog, char *sname, int permu, char **precompilerconstants, char *vert, char *frag);
int D3D9Shader_FindUniform(union programhandle_u *h, int type, char *name);
@ -574,6 +575,7 @@ void D3D11BE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize);
void D3D11BE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray);
void D3D11BE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray);
void D3D11BE_VBO_Destroy(vboarray_t *vearray);
void D3D11BE_Scissor(srect_t *rect);
#endif
//Asks the backend to invoke DrawMeshChain for each surface, and to upload lightmaps as required

Some files were not shown because too many files have changed in this diff Show More