cmake now builds botlib (as a shared object)

fix q3 looping sounds
fix q3sv bug that was kicking clients on map changes
attempt to resize q3ui if the window changes size
added some more disconnect reasons (for menuqc/q3ui to report).
reworked particle count/step arguments for better compat with DP. particles that used count for trails were already broken...
drawtextfield builtin will report line numbers shown, so qc can finally tell how much text there actually was
added some more items to 'fps_preset dp', stuff needed for the 'quake15' mod.
added dpcompat_noretouchground cvar for people wanting to mimic dp's bugs.
added 'r_netgraph 2' setting, which will show packet sizes per svc, in part to highlight wasteful mods.
added cvar to disable the q1mdl floodfill, which caused problems for yet another person.
internal editor now attempts to support debugging asm, if no source is available.
fix 64bit icon bug in x11.
FINALLY fix high's te_teleport effect.
load with no arguments will scan for the most recent a#/s#/quick savedgame instead of using just quick.
load command will chose between fte and vanilla savedgame formats based on modification time, if both exist in the same package/dir.



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5394 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-01-29 07:18:07 +00:00
parent c87535ecef
commit cd97d1fff3
49 changed files with 892 additions and 270 deletions

View File

@ -648,6 +648,41 @@ SET(FTE_CLIENT_FILES
engine/vk/vk_init.c
)
ADD_LIBRARY(fteq3bot MODULE
engine/botlib/be_aas_bspq3.c
engine/botlib/be_aas_entity.c
engine/botlib/be_aas_move.c
engine/botlib/be_aas_routealt.c
engine/botlib/be_ai_char.c
engine/botlib/be_ai_goal.c
engine/botlib/be_ai_weight.c
engine/botlib/l_crc.c
engine/botlib/l_memory.c
engine/botlib/l_struct.c
engine/botlib/be_aas_cluster.c
engine/botlib/be_aas_file.c
engine/botlib/be_aas_optimize.c
engine/botlib/be_aas_route.c
engine/botlib/be_ai_chat.c
engine/botlib/be_ai_move.c
engine/botlib/be_ea.c
engine/botlib/l_libvar.c
engine/botlib/l_precomp.c
engine/botlib/be_aas_debug.c
engine/botlib/be_aas_main.c
engine/botlib/be_aas_reach.c
engine/botlib/be_aas_sample.c
engine/botlib/be_ai_gen.c
engine/botlib/be_ai_weap.c
engine/botlib/be_interface.c
engine/botlib/l_log.c
engine/botlib/l_script.c
engine/botlib/standalone.c
)
SET_TARGET_PROPERTIES(fteq3bot PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_DEFINES};${FTE_REVISON};BOTLIB;EXTERNALBOTLIB")
TARGET_LINK_LIBRARIES(fteq3bot ${FTE_LIBS} )
SET_TARGET_PROPERTIES(fteq3bot PROPERTIES LINK_FLAGS "-Wl,--no-undefined")
FILE(STRINGS "${FTE_BUILD_CONFIG}" BULLET_INTERNAL REGEX "^#define[\t ]+USE_INTERNAL_BULLET")
IF(BULLET_INTERNAL)
#Built-in bullet physics plugin...

View File

@ -868,6 +868,13 @@ static void Init_AI_Export( ai_export_t *ai ) {
GetBotLibAPI
============
*/
#ifdef EXTERNALBOTLIB
#ifdef _WIN32
__declspec(dllexport)
#else
__attribute__((visibility("default")))
#endif
#endif
botlib_export_t *QDECL GetBotLibAPI(int apiVersion, botlib_import_t *import) {
assert(import);
botimport = *import;

View File

@ -203,6 +203,8 @@ typedef struct botlib_import_s
//
int (*DebugPolygonCreate)(int color, int numPoints, vec3_t *points);
void (*DebugPolygonDelete)(int id);
void (*Error)(const char *msg); //for unrecoverable errors only. Will quit out.
} botlib_import_t;
typedef struct aas_export_s

View File

@ -277,7 +277,7 @@ token_t *PC_CopyToken(token_t *token)
#ifdef BSPC
Error("out of token space\n");
#else
Com_Error(ERR_FATAL, "out of token space");
botimport.Error("out of token space");
#endif
return NULL;
} //end if
@ -561,7 +561,7 @@ void PC_PrintDefineHashTable(define_t **definehash)
int PC_NameHash(char *name)
{
int register hash, i;
register int hash, i;
hash = 0;
for (i = 0; name[i] != '\0'; i++)

198
engine/botlib/standalone.c Normal file
View File

@ -0,0 +1,198 @@
//license GPLv2+
//this file allows botlib to link as a dynamic lib with no external dependancies
#include "q_shared.h"
#include "botlib.h"
vec3_t vec3_origin;
void QDECL AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
{
float angle;
float sr, sp, sy, cr, cp, cy;
angle = angles[YAW] * (M_PI*2 / 360);
sy = sin(angle);
cy = cos(angle);
angle = angles[PITCH] * (M_PI*2 / 360);
sp = sin(angle);
cp = cos(angle);
angle = angles[ROLL] * (M_PI*2 / 360);
sr = sin(angle);
cr = cos(angle);
if (forward)
{
forward[0] = cp*cy;
forward[1] = cp*sy;
forward[2] = -sp;
}
if (right)
{
right[0] = (-1*sr*sp*cy+-1*cr*-sy);
right[1] = (-1*sr*sp*sy+-1*cr*cy);
right[2] = -1*sr*cp;
}
if (up)
{
up[0] = (cr*sp*cy+-sr*-sy);
up[1] = (cr*sp*sy+-sr*cy);
up[2] = cr*cp;
}
}
void QDECL VectorAngles(float *forward, float *up, float *result, qboolean meshpitch)
{
float yaw, pitch, roll;
if (forward[1] == 0 && forward[0] == 0)
{
if (forward[2] > 0)
{
pitch = -M_PI * 0.5;
yaw = up ? atan2(-up[1], -up[0]) : 0;
}
else
{
pitch = M_PI * 0.5;
yaw = up ? atan2(up[1], up[0]) : 0;
}
roll = 0;
}
else
{
yaw = atan2(forward[1], forward[0]);
pitch = -atan2(forward[2], sqrt (forward[0]*forward[0] + forward[1]*forward[1]));
if (up)
{
vec_t cp = cos(pitch), sp = sin(pitch);
vec_t cy = cos(yaw), sy = sin(yaw);
vec3_t tleft, tup;
tleft[0] = -sy;
tleft[1] = cy;
tleft[2] = 0;
tup[0] = sp*cy;
tup[1] = sp*sy;
tup[2] = cp;
roll = -atan2(DotProduct(up, tleft), DotProduct(up, tup));
}
else
roll = 0;
}
pitch *= 180 / M_PI;
yaw *= 180 / M_PI;
roll *= 180 / M_PI;
// if (meshpitch)
// pitch *= r_meshpitch.value;
if (pitch < 0)
pitch += 360;
if (yaw < 0)
yaw += 360;
if (roll < 0)
roll += 360;
result[0] = pitch;
result[1] = yaw;
result[2] = roll;
}
vec_t QDECL VectorNormalize2 (const vec3_t v, vec3_t out)
{
float length, ilength;
length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
length = sqrt (length);
if (length)
{
ilength = 1/length;
out[0] = v[0]*ilength;
out[1] = v[1]*ilength;
out[2] = v[2]*ilength;
}
else
{
VectorClear (out);
}
return length;
}
float QDECL VectorNormalize (vec3_t v)
{
return VectorNormalize2(v,v);
}
void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...)
{
va_list argptr;
va_start (argptr, fmt);
vsnprintf (dest, size, fmt, argptr);
va_end (argptr);
}
int Q_strncasecmp (const char *s1, const char *s2, int n)
{
int c1, c2;
while (1)
{
c1 = *s1++;
c2 = *s2++;
if (!n--)
return 0; // strings are equal until end point
if (c1 != c2)
{
if (c1 >= 'a' && c1 <= 'z')
c1 -= ('a' - 'A');
if (c2 >= 'a' && c2 <= 'z')
c2 -= ('a' - 'A');
if (c1 != c2)
{ // strings not equal
if (c1 > c2)
return 1; // strings not equal
return -1;
}
}
if (!c1)
return 0; // strings are equal
// s1++;
// s2++;
}
return -1;
}
int QDECL Q_stricmp (const char *s1, const char *s2)
{
return Q_strncasecmp (s1, s2, 0x7fffffff);
}
void QDECL Q_strncpyz(char *d, const char *s, int n)
{
int i;
n--;
if (n < 0)
return; //this could be an error
for (i=0; *s; i++)
{
if (i == n)
break;
*d++ = *s++;
}
*d='\0';
}
char *QDECL va(char *format, ...)
{
#define VA_BUFFER_SIZE 1024
va_list argptr;
static char string[VA_BUFFER_SIZE];
va_start (argptr, format);
vsnprintf (string,sizeof(string)-1, format,argptr);
va_end (argptr);
return string;
}

View File

@ -476,6 +476,99 @@ int CG_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projecti
return ctx.numfrags;
}
//called by the sound code.
static struct
{
unsigned int entnum;
vec3_t origin;
// vec3_t velocity;
sfx_t *sfx;
qboolean ispersistent;
} *loopers;
static size_t numloopers;
static size_t maxloopers;
unsigned int CG_GatherLoopingSounds(vec3_t *positions, unsigned int *entnums, sfx_t **sounds, unsigned int max)
{
size_t i;
if (max > numloopers)
max = numloopers;
for (i = 0; i < max; i++)
{
entnums[i] = loopers[i].entnum;
VectorCopy(loopers[i].origin, positions[i]);
sounds[i] = loopers[i].sfx;
}
return i;
}
static void CG_StopLoopingSounds(unsigned int entnum)
{
size_t i;
for (i = 0; i < numloopers; i++)
{
if (loopers[i].entnum == entnum)
break;
}
if (i == numloopers)
return;
loopers[i] = loopers[numloopers-1];
numloopers--;
}
static void CG_StartLoopingSounds(unsigned int entnum, float *origin, float *velocity, const char *soundname, qboolean persistent)
{
size_t i;
for (i = 0; i < numloopers; i++)
{
if (loopers[i].entnum == entnum)
break;
}
if (i == numloopers)
{
if (numloopers == maxloopers)
Z_ReallocElements((void**)&loopers, &maxloopers, maxloopers+1, sizeof(*loopers));
numloopers++;
}
loopers[i].entnum = entnum;
VectorCopy(origin, loopers[i].origin);
//VectorCopy(velocity, loopers[i].velocity);
loopers[i].sfx = S_PrecacheSound(soundname);
loopers[i].ispersistent = persistent;
}
static void CG_MoveLoopingSound(unsigned int entnum, float *origin)
{
size_t i;
for (i = 0; i < numloopers; i++)
{
if (loopers[i].entnum == entnum)
break;
}
if (i == numloopers)
return;
VectorCopy(origin, loopers[i].origin);
}
static void CG_ClearLoopingSounds(qboolean clearall)
{
if (clearall)
numloopers = 0;
else
{
size_t i;
for (i = 0; i < numloopers; )
{
if (!loopers[i].ispersistent)
{
loopers[i] = loopers[numloopers-1];
numloopers--;
}
else
i++;
}
}
}
int VM_LerpTag(void *out, model_t *model, int f1, int f2, float l2, char *tagname);
#define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) Host_EndGame("Call to cgame trap %u passes invalid pointer\n", (unsigned int)fn); //out of bounds.
@ -923,15 +1016,23 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
case CG_S_ADDLOOPINGSOUND:
//entnum, origin, velocity, sfx
// Con_DPrintf("CG_S_ADDLOOPINGSOUND: not implemented\n");
CG_StartLoopingSounds(VM_LONG(arg[0])+1, VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_FROMSTRCACHE(arg[3]), false);
break;
case CG_S_ADDREALLOOPINGSOUND:
//entnum, origin, velocity, sfx
// Con_DPrintf("CG_S_ADDREALLOOPINGSOUND: not implemented\n");
CG_StartLoopingSounds(VM_LONG(arg[0])+1, VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_FROMSTRCACHE(arg[3]), true);
break;
case CG_S_STOPLOOPINGSOUND:
//entnum
// Con_DPrintf("CG_S_STOPLOOPINGSOUND: not implemented\n");
CG_StopLoopingSounds(VM_LONG(arg[0])+1);
break;
case CG_S_CLEARLOOPINGSOUNDS:
//clearall
CG_ClearLoopingSounds(VM_LONG(arg[0]));
break;
case CG_S_UPDATEENTITYPOSITION://void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin );
//entnum, org
CG_MoveLoopingSound(VM_LONG(arg[0])+1, VM_POINTER(arg[1]));
break;
case CG_S_STARTBACKGROUNDTRACK:
@ -940,23 +1041,16 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
case CG_S_STOPBACKGROUNDTRACK:
Media_NamedTrack(NULL, NULL);
return 0;
case CG_S_CLEARLOOPINGSOUNDS:
//clearall
Con_DPrintf("CG_S_CLEARLOOPINGSOUNDS: not implemented\n");
break;
case CG_S_UPDATEENTITYPOSITION://void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin );
//entnum, org
// Con_DPrintf("CG_S_UPDATEENTITYPOSITION: not implemented\n");
break;
case CG_S_RESPATIALIZE://void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
{
int entnum = VM_LONG(arg[0])+1;
float *org = VM_POINTER(arg[1]);
vec3_t *axis = VM_POINTER(arg[2]);
int inwater = VM_LONG(arg[3]);
cl.playerview[0].audio.defaulted = false;
cl.playerview[0].audio.entnum = VM_LONG(arg[0])+1;
cl.playerview[0].audio.entnum = entnum;
VectorCopy(org, cl.playerview[0].audio.origin);
VectorCopy(axis[0], cl.playerview[0].audio.forward);
VectorCopy(axis[1], cl.playerview[0].audio.right);
@ -1142,7 +1236,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
case CG_FTE_SPAWNPARTICLEEFFECT:
return pe->RunParticleEffectState(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_FLOAT(arg[2]), VM_LONG(arg[3]), VM_POINTER(arg[4]));
case CG_FTE_SPAWNPARTICLETRAIL:
return pe->ParticleTrail(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2]), 0, NULL, VM_POINTER(arg[3]));
return pe->ParticleTrail(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2]), 0, 1, NULL, VM_POINTER(arg[3]));
case CG_FTE_FREEPARTICLESTATE:
pe->DelinkTrailstate(VM_POINTER(arg[0]));
break;

View File

@ -3894,6 +3894,7 @@ void CL_LinkPacketEntities (void)
int trailef, trailidx;
int modelflags;
struct itemtimer_s *timer, **timerlink;
float timestep = host_frametime;
pack = cl.currentpackentities;
if (!pack)
@ -4023,7 +4024,7 @@ void CL_LinkPacketEntities (void)
CL_NewDlight(state->number, ent->origin, radius, 0.1, colour[0], colour[1], colour[2]);
}
}
if (state->lightpflags & (PFLAGS_FULLDYNAMIC|PFLAGS_CORONA))
if ((state->lightpflags & (PFLAGS_FULLDYNAMIC|PFLAGS_CORONA)) && ((state->lightpflags&PFLAGS_FULLDYNAMIC)||state->light[3]))
{
vec3_t colour;
if (!state->light[0] && !state->light[1] && !state->light[2])
@ -4380,9 +4381,9 @@ void CL_LinkPacketEntities (void)
//and emit it
// if (lasttime != cl.currentpacktime)
{
if (trailef == P_INVALID || pe->ParticleTrail (old_origin, ent->origin, trailef, ent->keynum, ent->axis, &(le->trailstate)))
if (trailef == P_INVALID || pe->ParticleTrail (old_origin, ent->origin, trailef, timestep, ent->keynum, ent->axis, &(le->trailstate)))
if (model->traildefaultindex >= 0)
pe->ParticleTrailIndex(old_origin, ent->origin, P_INVALID, trailidx, 0, &(le->trailstate));
pe->ParticleTrailIndex(old_origin, ent->origin, P_INVALID, timestep, trailidx, 0, &(le->trailstate));
//dlights are not so customisable.
if (r_rocketlight.value && (modelflags & MF_ROCKET) && !(state->lightpflags & (PFLAGS_FULLDYNAMIC|PFLAGS_CORONA)))

View File

@ -55,7 +55,7 @@ cvar_t cl_timeout = CVAR("cl_timeout", "60");
cvar_t cl_shownet = CVARD("cl_shownet","0", "Debugging var. 0 shows nothing. 1 shows incoming packet sizes. 2 shows individual messages. 3 shows entities too."); // can be 0, 1, or 2
cvar_t cl_disconnectreason = CVARFD("_cl_disconnectreason", "", CVAR_NOSAVE, "This cvar contains the reason for the last disconnection, so that mod menus can know why things failed.");
cvar_t cl_disconnectreason = CVARAFD("_cl_disconnectreason", "", "com_errorMessage", CVAR_NOSAVE, "This cvar contains the reason for the last disconnection, so that mod menus can know why things failed.");
cvar_t cl_pure = CVARD("cl_pure", "0", "0=standard quake rules.\n1=clients should prefer files within packages present on the server.\n2=clients should use *only* files within packages present on the server.\nDue to quake 1.01/1.06 differences, a setting of 2 is only reliable with total conversions.\nIf sv_pure is set, the client will prefer the highest value set.");
cvar_t cl_sbar = CVARFC("cl_sbar", "0", CVAR_ARCHIVE, CL_Sbar_Callback);
@ -1046,6 +1046,7 @@ void CL_CheckForResend (void)
if (!NET_StringToAdr (host, connectinfo.defaultport, &connectinfo.adr))
{
Cvar_Set(&cl_disconnectreason, va("Bad server address \"%s\"", host));
Con_TPrintf ("Bad server address \"%s\"\n", host);
connectinfo.trying = false;
SCR_EndLoadingPlaque();
@ -1072,6 +1073,7 @@ void CL_CheckForResend (void)
}
if (!NET_IsClientLegal(&connectinfo.adr))
{
Cvar_Set(&cl_disconnectreason, va("Illegal server address"));
Con_TPrintf ("Illegal server address\n");
SCR_EndLoadingPlaque();
connectinfo.trying = false;
@ -1101,6 +1103,7 @@ void CL_CheckForResend (void)
if (connectinfo.tries == 0)
if (!NET_EnsureRoute(cls.sockets, "conn", cls.servername, &connectinfo.adr))
{
Cvar_Set(&cl_disconnectreason, va("Unable to establish connection to %s\n", cls.servername));
Con_Printf ("Unable to establish connection to %s\n", cls.servername);
connectinfo.trying = false;
SCR_EndLoadingPlaque();
@ -1171,6 +1174,7 @@ void CL_CheckForResend (void)
if (!keeptrying)
{
Cvar_Set(&cl_disconnectreason, va("No route to \"%s\", giving up\n", cls.servername));
Con_TPrintf ("No route to host, giving up\n");
connectinfo.trying = false;
SCR_EndLoadingPlaque();
@ -2960,18 +2964,27 @@ void CL_ConnectionlessPacket (void)
char *data = MSG_ReadStringLine();
Con_Printf ("reject\n%s\n", data);
if (NET_CompareAdr(&connectinfo.adr, &net_from))
{
Cvar_Set(&cl_disconnectreason, va("%s\n", data));
connectinfo.trying = false;
}
return;
}
else if (!strcmp(s, "badname"))
{ //rejected purely because of player name
if (NET_CompareAdr(&connectinfo.adr, &net_from))
{
Cvar_Set(&cl_disconnectreason, va("bad player name\n"));
connectinfo.trying = false;
}
}
else if (!strcmp(s, "badaccount"))
{ //rejected because username or password is wrong
if (NET_CompareAdr(&connectinfo.adr, &net_from))
{
Cvar_Set(&cl_disconnectreason, va("invalid username or password\n"));
connectinfo.trying = false;
}
}
Con_Printf ("f%s\n", s);
@ -3206,6 +3219,7 @@ void CL_ConnectionlessPacket (void)
}
if (connectinfo.dtlsupgrade == DTLS_REQUIRE)
{
Cvar_Set(&cl_disconnectreason, va("Server does not support/allow dtls. not connecting\n"));
connectinfo.trying = false;
Con_Printf("Server does not support/allow dtls. not connecting.\n");
return;

View File

@ -43,6 +43,12 @@ static int cl_dp_csqc_progscrc;
static int cl_dp_serverextension_download;
#endif
//tracks which svcs are using what data (per second)
static size_t packetusage_saved[256];
static size_t packetusage_pending[256];
static double packetusageflushtime;
static const double packetusage_interval=10;
#ifdef AVAIL_ZLIB
#ifndef ZEXPORT
#define ZEXPORT VARGS
@ -51,7 +57,7 @@ static int cl_dp_serverextension_download;
#endif
static char *svc_qwstrings[] =
static const char *svc_qwstrings[] =
{
"svc_bad",
"svc_nop",
@ -182,7 +188,7 @@ static char *svc_qwstrings[] =
};
#ifdef NQPROT
static char *svc_nqstrings[] =
static const char *svc_nqstrings[] =
{
"nqsvc_bad",
"nqsvc_nop",
@ -6701,6 +6707,7 @@ void CLQW_ParseServerMessage (void)
qboolean csqcpacket = false;
inframe_t *inf;
extern vec3_t demoangles;
unsigned int cmdstart;
received_framecount = host_framecount;
cl.last_servermessage = realtime;
@ -6751,6 +6758,13 @@ void CLQW_ParseServerMessage (void)
}
}
if (realtime > packetusageflushtime)
{
memcpy(packetusage_saved, packetusage_pending, sizeof(packetusage_saved));
memset(packetusage_pending, 0, sizeof(packetusage_pending));
packetusageflushtime = realtime + packetusage_interval;
}
//
// parse the message
//
@ -6763,6 +6777,7 @@ void CLQW_ParseServerMessage (void)
break;
}
cmdstart = msg_readcount;
cmd = MSG_ReadByte ();
if (cmd == svcfte_choosesplitclient)
@ -7267,6 +7282,8 @@ void CLQW_ParseServerMessage (void)
Con_Printf("Unable to parse gamecode packet\n");
break;
}
packetusage_pending[cmd] += msg_readcount-cmdstart;
}
}
@ -8282,3 +8299,57 @@ void CLNQ_ParseServerMessage (void)
}
#endif
struct sortedsvcs_s
{
const char *name;
size_t bytes;
};
static QDECL int sorttraffic(const void *l, const void *r)
{
const struct sortedsvcs_s *a=l, *b=r;
if (a->bytes==b->bytes)
return 0;
if (a->bytes>b->bytes)
return -1;
return 1;
}
void CL_ShowTrafficUsage(float x, float y)
{
const char **svcnames, *n;
size_t svccount, i, j=0;
size_t total;
struct sortedsvcs_s sorted[256];
if (cls.protocol == CP_NETQUAKE)
{
svcnames = svc_nqstrings;
svccount = countof(svc_nqstrings);
}
else
{
svcnames = svc_qwstrings;
svccount = countof(svc_qwstrings);
}
total = 0;
for (i = 0; i < 256; i++)
total += packetusage_saved[i];
for (i = 0; i < 256; i++)
{
if (!packetusage_saved[i])
continue; //don't show if there's no point.
if (i < svccount)
n = svcnames[i];
else
n = va("svc %u", (unsigned)i);
sorted[j].name = n;
sorted[j].bytes = packetusage_saved[i];
j++;
}
qsort(sorted, j, sizeof(*sorted), sorttraffic);
for (i = 0; i < j; i++)
{
Draw_FunString(x, y, va("%22s:%5.1f%% (%.0f/s)", sorted[i].name, (100.0*sorted[i].bytes)/total, (sorted[i].bytes/packetusage_interval)));
y+=8;
}
}

View File

@ -648,7 +648,7 @@ static char *SCR_CopyCenterPrint(cprint_t *p) //reads the link under the mouse c
}
#define MAX_CPRINT_LINES 512
void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
int SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
{
int l;
int y, x;
@ -794,6 +794,8 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
}
Font_EndString(font);
return linecount;
}
qboolean Key_Centerprint(int key, int unicode, unsigned int devid)
@ -904,7 +906,7 @@ void SCR_CheckDrawCenterString (void)
}
}
void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags, struct font_s *font, vec2_t fontscale)
int R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags, struct font_s *font, vec2_t fontscale)
{
cprint_t p;
vrect_t r;
@ -923,7 +925,7 @@ void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int
p.time_start = cl.time;
*p.titleimage = 0;
SCR_DrawCenterString(&r, &p, font);
return SCR_DrawCenterString(&r, &p, font);
}
qboolean SCR_HardwareCursorIsActive(void)

View File

@ -776,8 +776,8 @@ beam_t *CL_AddBeam (enum beamtype_e tent, int ent, vec3_t start, vec3_t end) //f
if (ent < 0 && ent >= -512) //a zquake concept. ent between -1 and -maxplayers is to be taken to be a railtrail from a particular player instead of a beam.
{
// TODO: add support for those finnicky colored railtrails...
if (P_ParticleTrail(start, end, rtqw_railtrail, -ent, NULL, NULL))
P_ParticleTrailIndex(start, end, P_INVALID, 208, 8, NULL);
if (P_ParticleTrail(start, end, rtqw_railtrail, 0.1, -ent, NULL, NULL))
P_ParticleTrailIndex(start, end, P_INVALID, 0.1, 208, 8, NULL);
return NULL;
}
break;
@ -1607,8 +1607,8 @@ void CL_ParseTEnt (void)
pos2[1] = MSG_ReadCoord ();
pos2[2] = MSG_ReadCoord ();
if (P_ParticleTrail(pos, pos2, rtqw_railtrail, 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, P_INVALID, 208, 8, NULL);
if (P_ParticleTrail(pos, pos2, rtqw_railtrail, 1, 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, P_INVALID, 1, 208, 8, NULL);
break;
case TEH2_STREAM_LIGHTNING_SMALL:
@ -1751,8 +1751,8 @@ void CL_ParseTEnt (void)
MSG_ReadCoord ();
MSG_ReadCoord ();
if (P_ParticleTrail(pos, pos2, P_FindParticleType("te_nexbeam"), 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, P_INVALID, 15, 0, NULL);
if (P_ParticleTrail(pos, pos2, P_FindParticleType("te_nexbeam"), 1, 0, NULL, NULL))
P_ParticleTrailIndex(pos, pos2, P_INVALID, 1, 15, 0, NULL);
break;
case TEDP_SMOKE:
@ -1933,7 +1933,7 @@ void CL_SpawnCustomTEnt(custtentinst_t *info)
}
}
else
failed = P_ParticleTrail(info->pos, info->pos2, t->particleeffecttype, 0, NULL, NULL);
failed = P_ParticleTrail(info->pos, info->pos2, t->particleeffecttype, 1, 0, NULL, NULL);
}
else
{
@ -2262,8 +2262,8 @@ void CL_ParseTrailParticles(void)
else
ts = NULL;
if (P_ParticleTrail(start, end, effectindex, entityindex, NULL, ts))
P_ParticleTrail(start, end, rt_blood, entityindex, NULL, ts);
if (P_ParticleTrail(start, end, effectindex, 1, entityindex, NULL, ts))
P_ParticleTrail(start, end, rt_blood, 1, entityindex, NULL, ts);
}
void CL_ParsePointParticles(qboolean compact)
@ -2588,7 +2588,7 @@ void CLQ2_ParseTEnt (void)
case Q2TE_BLUEHYPERBLASTER: //TE_BLASTER without model+light
MSG_ReadPos (pos);
MSG_ReadPos (pos2);
P_ParticleTrail(pos, pos2, pt, 0, NULL, NULL);
P_ParticleTrail(pos, pos2, pt, 1, 0, NULL, NULL);
break;
case Q2TE_EXPLOSION1: //column
case Q2TE_EXPLOSION2: //splits
@ -2674,13 +2674,13 @@ void CLQ2_ParseTEnt (void)
MSG_ReadPos (pos);
MSG_ReadPos (pos2);
color = MSG_ReadByte ();
P_ParticleTrailIndex(pos, pos2, pt, color, 0, NULL);
P_ParticleTrailIndex(pos, pos2, pt, 1, color, 0, NULL);
break;
case Q2TE_FLASHLIGHT: //white 400-radius dlight
MSG_ReadPos(pos);
ent = MSG_ReadShort();
P_ParticleTrail(pos, pos, pt, ent, NULL, NULL);
P_ParticleTrail(pos, pos, pt, 1, ent, NULL, NULL);
break;
case Q2TE_WIDOWBEAMOUT: /*requires state tracking to keep it splurting constantly for 2.1 secs*/
ent = MSG_ReadShort();
@ -2737,7 +2737,7 @@ void CLQ2_ParseTEnt (void)
case CRTE_BLASTERBEAM:
MSG_ReadPos (pos);
MSG_ReadPos (pos2);
P_ParticleTrail(pos, pos2, P_FindParticleType("q2part.TR_BLASTERTRAIL2"), 0, NULL, NULL);
P_ParticleTrail(pos, pos2, P_FindParticleType("q2part.TR_BLASTERTRAIL2"), 1, 0, NULL, NULL);
break;
/* case CRTE_STAIN:
Host_EndGame ("CLQ2_ParseTEnt: bad/non-implemented type %i", type);
@ -2969,7 +2969,7 @@ void CL_UpdateBeams (void)
}
if (ruleset_allow_particle_lightning.ival || !type->modelname)
if (type->ef_beam >= 0 && !P_ParticleTrail(org, b->end, type->ef_beam, b->entity, NULL, &b->trailstate))
if (type->ef_beam >= 0 && !P_ParticleTrail(org, b->end, type->ef_beam, host_frametime, b->entity, NULL, &b->trailstate))
continue;
if (!type->model)
{
@ -3151,7 +3151,7 @@ void CL_UpdateExplosions (void)
#endif
if (ex->traileffect != P_INVALID)
pe->ParticleTrail(ent->oldorigin, ent->origin, ex->traileffect, 0, ent->axis, &(ex->trailstate));
pe->ParticleTrail(ent->oldorigin, ent->origin, ex->traileffect, frametime, 0, ent->axis, &(ex->trailstate));
if (!(ex->flags & Q2RF_BEAM))
VectorCopy(ent->origin, ex->oldorigin); //don't corrupt q2 beams
if (ex->flags & Q2RF_BEAM)

View File

@ -28,6 +28,7 @@ typedef struct {
} script_t;
static script_t *scripts;
static int maxscripts;
static unsigned int ui_width, ui_height; //to track when it needs to be restarted (the api has no video mode changed event)
#define Q3SCRIPTPUNCTUATION "(,{})(\':;=!><&|+-\""
void StripCSyntax (char *s)
{
@ -1483,6 +1484,12 @@ void UI_DrawMenu(void)
{
if (uivm)
{
if (qrenderer != QR_NONE && (ui_width != vid.width || ui_height != vid.height))
{
ui_width = vid.width;
ui_height = vid.height;
VM_Call(uivm, UI_INIT);
}
VM_Call(uivm, UI_REFRESH, (int)(realtime * 1000));
}
}
@ -1585,11 +1592,14 @@ qboolean UI_KeyPress(int key, int unicode, qboolean down)
// return result;
}
qboolean UI_MousePosition(int xpos, int ypos)
qboolean UI_MousePosition(float xpos, float ypos)
{
if (uivm && (keycatcher&2))
{
VM_Call(uivm, UI_MOUSE_EVENT, (xpos)*640/(int)vid.width, (ypos)*480/(int)vid.height);
int px, py;
px = (xpos);//*640/(int)vid.width;
py = (ypos);//*480/(int)vid.height;
VM_Call(uivm, UI_MOUSE_EVENT, px, py);
return true;
}
return false;
@ -1625,6 +1635,8 @@ void UI_Start (void)
for (i = 0; i < MAX_PINGREQUESTS; i++)
ui_pings[i].type = NA_INVALID;
ui_width = vid.width;
ui_height = vid.height;
uivm = VM_Create("vm/ui", com_nogamedirnativecode.ival?NULL:UI_SystemCallsNative, UI_SystemCallsVM);
if (uivm)
{

View File

@ -1282,6 +1282,7 @@ void CLNQ_ParseServerMessage (void);
#ifdef Q2CLIENT
void CLQ2_ParseServerMessage (void);
#endif
void CL_ShowTrafficUsage(float x, float y);
void CL_NewTranslation (int slot);
int CL_IsDownloading(const char *localname);

View File

@ -1779,6 +1779,8 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
unsigned int effects, renderfx;
float back, fwds;
float timestep = cl.gametime-cl.oldgametime;
// bonus items rotate at a fixed rate
autorotate = anglemod(cl.time*100);
@ -2206,10 +2208,10 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
if (effects & Q2EF_ROCKET)
{
//FIXME: cubemap orientation
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_ROCKET], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_rocket, ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_ROCKET], timestep, ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_rocket, timestep, ent.keynum, NULL, &cent->trailstate))
{
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 0xdc, 4, &cent->trailstate);
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 0xdc, 4, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 200, 0.2, 0.1, 0.05);
}
}
@ -2220,17 +2222,17 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
//PGM
if (effects & Q2EF_TRACKER) // lame... problematic?
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_BLASTERTRAIL2], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_BLASTERTRAIL2], timestep, ent.keynum, NULL, &cent->trailstate))
{
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 0xd0, 1, &cent->trailstate);
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 0xd0, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 200, 0, 0.2, 0);
}
}
else
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_BLASTERTRAIL], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_BLASTERTRAIL], timestep, ent.keynum, NULL, &cent->trailstate))
{
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 0xe0, 1, &cent->trailstate);
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 0xe0, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 200, 0.2, 0.2, 0);
}
}
@ -2245,15 +2247,15 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
}
else if (effects & Q2EF_GIB)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_GIB], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_blood, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 0xe8, 8, &cent->trailstate);
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_GIB], timestep, ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_blood, timestep, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 0xe8, 8, &cent->trailstate);
}
else if (effects & Q2EF_GRENADE)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_GRENADE], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_grenade, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 4, 8, &cent->trailstate);
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_GRENADE], timestep, ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, rt_grenade, timestep, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 4, 8, &cent->trailstate);
}
else if (effects & Q2EF_FLIES)
{
@ -2278,21 +2280,21 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
else if (effects & Q2EF_TRAP)
{
ent.origin[2] += 32;
P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_TRAP], ent.keynum, NULL, &cent->trailstate);
P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_TRAP], timestep, ent.keynum, NULL, &cent->trailstate);
}
else if (effects & Q2EF_FLAG1)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_FLAG1], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_FLAG1], timestep, ent.keynum, NULL, &cent->trailstate))
{
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 242, 1, &cent->trailstate);
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 242, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 225, 0.2, 0.05, 0.05);
}
}
else if (effects & Q2EF_FLAG2)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_FLAG2], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_FLAG2], timestep, ent.keynum, NULL, &cent->trailstate))
{
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 115, 1, &cent->trailstate);
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 115, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 225, 0.05, 0.05, 0.2);
}
}
@ -2300,9 +2302,9 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
//ROGUE
else if (effects & Q2EF_TAGTRAIL)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_TAGTRAIL], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_TAGTRAIL], timestep, ent.keynum, NULL, &cent->trailstate))
{
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 220, 1, &cent->trailstate);
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 220, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 225, 0.2, 0.2, 0.0);
}
}
@ -2325,9 +2327,9 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
}
else if (effects & Q2EF_TRACKER)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_TRACKER], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_TRACKER], timestep, ent.keynum, NULL, &cent->trailstate))
{
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 0, 1, &cent->trailstate);
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 0, 1, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 200, -0.2, -0.2, -0.2);
}
}
@ -2336,15 +2338,15 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
// RAFAEL
else if (effects & Q2EF_GREENGIB)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_GREENGIB], ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 219, 8, &cent->trailstate);
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_GREENGIB], timestep, ent.keynum, NULL, &cent->trailstate))
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 219, 8, &cent->trailstate);
}
// RAFAEL
else if (effects & Q2EF_IONRIPPER)
{
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_IONRIPPER], ent.keynum, NULL, &cent->trailstate))
if (P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_IONRIPPER], timestep, ent.keynum, NULL, &cent->trailstate))
{
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, 228, 4, &cent->trailstate);
P_ParticleTrailIndex(cent->lerp_origin, ent.origin, P_INVALID, timestep, 228, 4, &cent->trailstate);
V_AddLight (ent.keynum, ent.origin, 100, 0.2, 0.1, 0.1);
}
}
@ -2358,7 +2360,7 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
{
if (effects & Q2EF_ANIM_ALLFAST)
{
P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_PLASMA], ent.keynum, NULL, &cent->trailstate);
P_ParticleTrail(cent->lerp_origin, ent.origin, pt_q2[Q2RT_PLASMA], timestep, ent.keynum, NULL, &cent->trailstate);
}
V_AddLight (ent.keynum, ent.origin, 130, 0.2, 0.1, 0.1);
}

View File

@ -549,7 +549,6 @@ void CLQ3_ParseGameState(void)
cl.maxpitch = 90;
ccs.lastServerCommandNum = MSG_ReadLong();
ccs.currentServerCommandNum = ccs.lastServerCommandNum;
for(;;)
{

View File

@ -219,7 +219,6 @@ typedef struct frame_s {
typedef struct {
int lastClientCommandNum;
int lastServerCommandNum;
int currentServerCommandNum;
int numClientCommands;
int serverMessageNum;

View File

@ -1068,11 +1068,28 @@ void FPS_Preset_f (void)
if (!stricmp("dp", arg))
{
if (sv.state)
Cbuf_InsertText("echo Be sure to restart your server\n", RESTRICT_LOCAL, false);
Cbuf_InsertText(
"set sv_listen_dp 1\n"
"set sv_bigcoords 1\n"
"set r_particledesc \"effectinfo classic\"\n"
"echo you may need to restart the map\n"
//these are for smc+derived mods
"sv_listen_dp 1\n" //awkward, but forces the server to load the effectinfo.txt in advance.
"sv_bigcoords 1\n" //for viewmodel lep precision (would be better to use csqc)
"r_particledesc \"effectinfo high\"\n" //blurgh.
"dpcompat_noretouchground 1\n" //don't call touch functions on entities that already appear onground. this also changes the order that the onground flag is set relative to touch functions.
"cl_nopred 1\n" //DP doesn't predict by default, and DP mods have a nasty habit of clearing .solid values during prethinks, which screws up prediction. so play safe.
"r_dynamic 0\nr_shadow_realtime_dlight 1\n" //fte has separate cvars for everything. which kinda surprises people and makes stuff twice as bright as it should be.
//general compat stuff
"dpcompat_console 1\n" //
"dpcompat_findradiusarealinks 1\n" //faster findradiuses (but that require things are setorigined properly)
"dpcompat_makeshitup 2\n" //flatten shaders to a single pass, then add new specular etc passes.
//"dpcompat_nopremulpics 1\n" //don't use premultiplied alpha (solving issues with compressed image formats)
"dpcompat_psa_ungroup 1\n" //don't use framegroups with psk models at all.
"dpcompat_set 1\n" //handle 3-arg sets differently
"dpcompat_stats 1\n" //truncate float stats
"dpcompat_strcat_limit 16383\n" //xonotic compat. maximum length of strcat strings.
// "sv_listen_dp 1\nsv_listen_nq 0\nsv_listen_qw 0\ncl_loopbackprotocol dpp7\ndpcompat_nopreparse 1\n"
, RESTRICT_LOCAL, false);
return;
}

View File

@ -139,7 +139,7 @@ extern void SCR_DrawConsole (qboolean noback);
extern void SCR_SetUpToDrawConsole (void);
extern void SCR_CenterPrint (int pnum, const char *str, qboolean skipgamecode);
void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags, struct font_s *font, vec2_t fontscale);
int R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags, struct font_s *font, vec2_t fontscale);
#define CPRINT_LALIGN (1<<0) //L
#define CPRINT_TALIGN (1<<1) //T
#define CPRINT_RALIGN (1<<2) //R

View File

@ -265,7 +265,7 @@ static void PClassic_RunParticleEffect4 (vec3_t org, float radius, int color, in
}
//this function is used as a fallback in case a trail effect is unknown.
static void PClassic_ParticleTrailIndex (vec3_t start, vec3_t end, int type, int color, int crnd, trailstate_t **tsk)
static void PClassic_ParticleTrailIndex (vec3_t start, vec3_t end, int type, float timestep, int color, int crnd, trailstate_t **tsk)
{
}
@ -1130,7 +1130,7 @@ int PClassic_PointFile(int c, vec3_t point)
}
//builds a trail from here to there. The trail state can be used to remember how far you got last frame.
static int PClassic_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk)
static int PClassic_ParticleTrail (vec3_t startpos, vec3_t end, int type, float timestep, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk)
{
float leftover;

View File

@ -12,7 +12,7 @@ static int PNULL_FindParticleType(const char *name)
}
static int PNULL_RunParticleEffectTypeString (vec3_t org, vec3_t dir, float count, char *name){return 1;}
static int PNULL_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk){return 1;}
static int PNULL_ParticleTrail (vec3_t startpos, vec3_t end, int type, float timestep, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk){return 1;}
static int PNULL_RunParticleEffectState (vec3_t org, vec3_t dir, float count, int typenum, trailstate_t **tsk){return 1;}
static void PNULL_RunParticleWeather(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, char *efname){}
static void PNULL_RunParticleCube(int typenum, vec3_t minb, vec3_t maxb, vec3_t dir_min, vec3_t dir_max, float count, int colour, qboolean gravity, float jitter){}
@ -22,7 +22,7 @@ static void PNULL_RunParticleEffect3 (vec3_t org, vec3_t box, int color, int eff
static void PNULL_RunParticleEffect4 (vec3_t org, float radius, int color, int effect, int count){}
static void PNULL_RunParticleEffectPalette (const char *nameprefix, vec3_t org, vec3_t dir, int color, int count){}
static void PNULL_ParticleTrailIndex (vec3_t start, vec3_t end, int type, int color, int crnd, trailstate_t **tsk){}
static void PNULL_ParticleTrailIndex (vec3_t start, vec3_t end, int type, float timestep, int color, int crnd, trailstate_t **tsk){}
static qboolean PNULL_InitParticles (void)
{

View File

@ -264,6 +264,8 @@ typedef struct part_type_s {
int countextra;
float count;
float countrand;
float countspacing; //for trails.
float countoverflow; //for badly-designed effects, instead of depending on trail state.
float rainfrequency;
int assoc;
@ -1368,12 +1370,14 @@ void P_ParticleEffect_f(void)
else if (!strcmp(var, "step"))
{
ptype->countspacing = atof(value);
ptype->count = 1/atof(value);
if (Cmd_Argc()>2)
ptype->countrand = 1/atof(Cmd_Argv(2));
}
else if (!strcmp(var, "count"))
{
ptype->countspacing = 0;
ptype->count = atof(value);
if (Cmd_Argc()>2)
ptype->countrand = atof(Cmd_Argv(2));
@ -2401,7 +2405,7 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen)
Q_strncatz(outstr, va("tcoords %g %g %g %g %g %i %g\n", ptype->s1, ptype->t1, ptype->s2, ptype->t2, 1.0f, ptype->randsmax, ptype->texsstride), outstrlen);
}
if (ptype->count || all)
if (ptype->count || ptype->countrand || ptype->countextra || all)
Q_strncatz(outstr, va("count %g %g %i\n", ptype->count, ptype->countrand, ptype->countextra), outstrlen);
if (ptype->rainfrequency != 1 || all)
Q_strncatz(outstr, va("rainfrequency %g\n", ptype->rainfrequency), outstrlen);
@ -3152,7 +3156,10 @@ static void P_ImportEffectInfo(char *config, char *line)
else if (!strcmp(arg[0], "velocitymultiplier") && args == 2)
ptype->veladd = atof(arg[1]);
else if (!strcmp(arg[0], "trailspacing") && args == 2)
ptype->count = 1 / atof(arg[1]);
{
ptype->countspacing = atof(arg[1]);
ptype->count = 1 / ptype->countspacing;
}
else if (!strcmp(arg[0], "time") && args == 3)
{
ptype->die = atof(arg[1]);
@ -5476,7 +5483,7 @@ static void PScript_RunParticleEffectPalette (const char *nameprefix, vec3_t org
}
}
static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype, trailstate_t **tsk, int dlkey, vec3_t dlaxis[3])
static void P_ParticleTrailSpawn (vec3_t startpos, vec3_t end, part_type_t *ptype, float timeinterval, trailstate_t **tsk, int dlkey, vec3_t dlaxis[3])
{
vec3_t vec, vstep, right, up, start;
float len;
@ -5528,9 +5535,9 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype
if (ptype->assoc>=0)
{
if (ts)
P_ParticleTrail(start, end, ptype->assoc, dlkey, NULL, &(ts->assoc));
P_ParticleTrail(start, end, ptype->assoc, timeinterval, dlkey, NULL, &(ts->assoc));
else
P_ParticleTrail(start, end, ptype->assoc, dlkey, NULL, NULL);
P_ParticleTrail(start, end, ptype->assoc, timeinterval, dlkey, NULL, NULL);
}
if (r_part_contentswitch.ival && (ptype->flags & (PT_TRUNDERWATER | PT_TROVERWATER)) && cl.worldmodel)
@ -5561,20 +5568,30 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype
if (!ptype->die)
ts = NULL;
// use ptype step to calc step vector and step size
step = (ptype->count*r_part_density.value) + ptype->countextra;
if (step>0)
{
step = 1/step;
if (step < 0.01)
step = 0.01;
}
else
step = 0;
VectorSubtract (end, start, vec);
len = VectorNormalize (vec);
// use ptype step to calc step vector and step size
if (ptype->countspacing)
{
step = ptype->countspacing; //particles per qu
step /= r_part_density.value; //scaled...
//FIXME: countextra
}
else
{
step = ptype->count * r_part_density.value * timeinterval;
step += ptype->countextra; //particles per frame
step += ptype->countoverflow;
count = (int)step;
ptype->countoverflow = step-count; //the part that we're forgetting, to add to the next frame...
if (count<=0)
return;
else
step = len/count; //particles per second
}
if (ptype->flags & PT_AVERAGETRAIL)
{
float tavg;
@ -5641,7 +5658,10 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype
step = 0;
VectorClear(vstep);
}
count += ptype->countextra;
// count += ptype->countextra;
if (count > 1000)
count = 1000;
while (count-->0)//len < stop)
{
@ -5992,14 +6012,14 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype
return;
}
static int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t axis[3], trailstate_t **tsk)
static int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, float timeinterval, int dlkey, vec3_t axis[3], trailstate_t **tsk)
{
part_type_t *ptype = &part_type[type];
// TODO: fallback particle system won't have a decent trailstate which will mess up
// high fps trails
if (type >= FALLBACKBIAS && fallback)
return fallback->ParticleTrail(startpos, end, type-FALLBACKBIAS, dlkey, axis, NULL);
return fallback->ParticleTrail(startpos, end, type-FALLBACKBIAS, timeinterval, dlkey, axis, NULL);
if (type < 0 || type >= numparticletypes)
return 1; //bad value
@ -6017,11 +6037,11 @@ static int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlk
ptype = &part_type[ptype->inwater];
}
P_ParticleTrailDraw (startpos, end, ptype, tsk, dlkey, axis);
P_ParticleTrailSpawn (startpos, end, ptype, timeinterval, tsk, dlkey, axis);
return 0;
}
static void PScript_ParticleTrailIndex (vec3_t start, vec3_t end, int type, int color, int crnd, trailstate_t **tsk)
static void PScript_ParticleTrailIndex (vec3_t start, vec3_t end, int type, float timeinterval, int color, int crnd, trailstate_t **tsk)
{
if (type == P_INVALID)
type = pe_defaulttrail;
@ -6029,7 +6049,7 @@ static void PScript_ParticleTrailIndex (vec3_t start, vec3_t end, int type, int
{
part_type[type].colorindex = color;
part_type[type].colorrand = crnd;
P_ParticleTrail(start, end, type, 0, NULL, tsk);
P_ParticleTrail(start, end, type, timeinterval, 0, NULL, tsk);
}
}
@ -7280,7 +7300,7 @@ static void PScript_DrawParticleTypes (void)
if (type->emit >= 0)
{
if (type->emittime < 0)
P_ParticleTrail(oldorg, p->org, type->emit, 0, NULL, &p->state.trailstate);
P_ParticleTrail(oldorg, p->org, type->emit, pframetime, 0, NULL, &p->state.trailstate);
else if (p->state.nextemit < particletime)
{
p->state.nextemit = particletime + type->emittime + frandom()*type->emitrand;

View File

@ -59,6 +59,8 @@ static csqctreadstate_t *csqcthreads;
qboolean csqc_resortfrags;
world_t csqc_world;
float csqc_starttime; //reset on each csqc reload to restore lost precision of cltime on each map restart.
int csqc_playerseat; //can be negative.
static playerview_t *csqc_playerview;
qboolean csqc_dp_lastwas3d; //to emulate DP correctly, we need to track whether drawpic/drawfill or clearscene was called last. blame 515.
@ -423,7 +425,7 @@ static void CSQC_FindGlobals(qboolean nofuncs)
if (csqcg.simtime)
*csqcg.simtime = cl.servertime;
if (csqcg.cltime)
*csqcg.cltime = realtime;
*csqcg.cltime = realtime-csqc_starttime;
if (!csqcg.global_gravitydir)
csqcg.global_gravitydir = defaultgravity;
@ -3199,7 +3201,7 @@ static void QCBUILTIN PF_cs_boxparticles(pubprogfuncs_t *prinst, struct globalva
if (flags & 128) //PARTICLES_DRAWASTRAIL
{
flags &= ~128;
P_ParticleTrail(org_from, org_to, effectnum, 0, NULL, NULL);
P_ParticleTrail(org_from, org_to, effectnum, 1, 0, NULL, NULL);
}
else
{
@ -3235,6 +3237,7 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa
csqcedict_t *ent;
float *start = G_VECTOR(OFS_PARM2);
float *end = G_VECTOR(OFS_PARM3);
float timestep = host_frametime;
if ((unsigned int)G_INT(OFS_PARM1) >= MAX_EDICTS)
{ //ents can't be negative, nor can they be huge (like floats are if expressed as an integer)
@ -3249,9 +3252,9 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa
efnum = CL_TranslateParticleFromServer(efnum);
if (!ent->entnum) //world trails are non-state-based.
pe->ParticleTrail(start, end, efnum, 0, NULL, NULL);
pe->ParticleTrail(start, end, efnum, timestep, 0, NULL, NULL);
else
pe->ParticleTrail(start, end, efnum, -ent->entnum, NULL, &ent->trailstate);
pe->ParticleTrail(start, end, efnum, timestep, -ent->entnum, NULL, &ent->trailstate);
}
void CSQC_ResetTrails(void)
@ -5064,9 +5067,9 @@ void CSQC_EntStateToCSQC(unsigned int flags, float lerptime, entity_state_t *src
//use entnum as a test to see if its new (if the old origin isn't usable)
if (ent->xv->entnum)
{
if (model->particletrail == P_INVALID || pe->ParticleTrail (ent->v->origin, src->origin, model->particletrail, src->number, NULL, &(le->trailstate)))
if (model->particletrail == P_INVALID || pe->ParticleTrail (ent->v->origin, src->origin, model->particletrail, host_frametime, src->number, NULL, &(le->trailstate)))
if (model->traildefaultindex >= 0)
pe->ParticleTrailIndex(ent->v->origin, src->origin, P_INVALID, model->traildefaultindex, 0, &(le->trailstate));
pe->ParticleTrailIndex(ent->v->origin, src->origin, P_INVALID, host_frametime, model->traildefaultindex, 0, &(le->trailstate));
}
}
@ -7331,6 +7334,10 @@ pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc)
csqc_isdarkplaces = true;
Con_DPrintf(CON_WARNING "Running darkplaces csprogs.dat version\n");
break;
case 23147:
csqc_isdarkplaces = true;
Con_DPrintf(CON_WARNING "Running ^aINVALID^a csprogs.dat version\n");
break;
#endif
default:
Con_Printf(CON_WARNING "Running unknown csprogs.dat version\n");
@ -7467,6 +7474,7 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec
int csaddonnum = -1;
in_sensitivityscale = 1;
csqcmapentitydataloaded = true;
csqc_starttime = realtime;
csqcprogs = InitProgs(&csqcprogparms);
csqc_world.progs = csqcprogs;
csqc_world.usesolidcorpse = true;
@ -8067,7 +8075,7 @@ qboolean CSQC_DrawView(void)
CL_PredictMove ();
if (csqcg.cltime)
*csqcg.cltime = realtime;
*csqcg.cltime = realtime-csqc_starttime;
if (csqcg.simtime)
*csqcg.simtime = cl.servertime;
if (csqcg.clientcommandframe)
@ -8156,7 +8164,7 @@ qboolean CSQC_DrawHud(playerview_t *pv)
if (csqcg.frametime)
*csqcg.frametime = host_frametime;
if (csqcg.cltime)
*csqcg.cltime = realtime;
*csqcg.cltime = realtime-csqc_starttime;
G_FLOAT(OFS_PARM0+0) = r_refdef.grect.width;
G_FLOAT(OFS_PARM0+1) = r_refdef.grect.height;
@ -8200,7 +8208,7 @@ qboolean CSQC_DrawScores(playerview_t *pv)
if (csqcg.frametime)
*csqcg.frametime = host_frametime;
if (csqcg.cltime)
*csqcg.cltime = realtime;
*csqcg.cltime = realtime-csqc_starttime;
G_FLOAT(OFS_PARM0+0) = r_refdef.grect.width;
G_FLOAT(OFS_PARM0+1) = r_refdef.grect.height;
@ -8629,7 +8637,7 @@ void CSQC_Input_Frame(int seat, usercmd_t *cmd)
if (csqcg.simtime)
*csqcg.simtime = cl.servertime;
if (csqcg.cltime)
*csqcg.cltime = realtime;
*csqcg.cltime = realtime-csqc_starttime;
if (csqcg.clientcommandframe)
*csqcg.clientcommandframe = cl.movesequence;
@ -8743,7 +8751,7 @@ void CSQC_ParseEntities(void)
if (csqcg.simtime) //estimated server time
*csqcg.simtime = cl.servertime;
if (csqcg.cltime) //smooth client time.
*csqcg.cltime = realtime;
*csqcg.cltime = realtime-csqc_starttime;
if (csqcg.netnewtime)
*csqcg.netnewtime = cl.gametime;

View File

@ -438,7 +438,7 @@ void QCBUILTIN PF_CL_DrawTextField (pubprogfuncs_t *prinst, struct globalvars_s
// Oversight ~eukara
R2D_ImageColours(1.0f, 1.0f, 1.0f, 1.0f);
R_DrawTextField(pos[0], pos[1], size[0], size[1], text, CON_WHITEMASK, flags, font, scale);
G_FLOAT(OFS_RETURN) = R_DrawTextField(pos[0], pos[1], size[0], size[1], text, CON_WHITEMASK, flags, font, scale);
}
//float drawstring(vector position, string text, vector scale, float alpha, float flag) = #455;

View File

@ -1728,7 +1728,6 @@ char *particle_set_high =
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"void main(void)\n"
"{\n"
"vec2 nst;\n"

View File

@ -29,6 +29,4 @@ extern char *particle_set_q2part;
extern char *particle_set_tsshaft;
#define R_PARTSET_BUILTINS_tsshaft {"tsshaft", &particle_set_tsshaft},
#define R_PARTSET_BUILTINS R_PARTSET_BUILTINS_spikeset R_PARTSET_BUILTINS_faithful R_PARTSET_BUILTINS_highfps R_PARTSET_BUILTINS_high R_PARTSET_BUILTINS_minimal R_PARTSET_BUILTINS_h2part R_PARTSET_BUILTINS_q2part R_PARTSET_BUILTINS_tsshaft
#else
#define R_PARTSET_BUILTINS
#endif

View File

@ -3495,6 +3495,11 @@ static void S_Q2_AddEntitySounds(soundcardinfo_t *sc)
if (cls.protocol == CP_QUAKE2)
count = CLQ2_GatherSounds(positions, entnums, sounds, countof(sounds));
else
#endif
#ifdef Q3CLIENT
if (cls.protocol == CP_QUAKE3)
count = CG_GatherLoopingSounds(positions, entnums, sounds, countof(sounds));
else
#endif
return;
@ -3548,7 +3553,11 @@ static void S_Q2_AddEntitySounds(soundcardinfo_t *sc)
}
if (sc->ChannelUpdate)
{ //hardware mixing doesn't support merging
VectorCopy(positions[count], c->origin);
SND_Spatialize(sc, c);
if (c->sfx)
sc->ChannelUpdate(sc, c, false);
}
else
{ //merge with any other ents, if we can

View File

@ -881,7 +881,7 @@ void Con_Editor_GoToLine(console_t *con, int line)
con->display = con->display->newer;
}
}
console_t *Con_TextEditor(const char *fname, const char *line, qboolean newfile)
console_t *Con_TextEditor(const char *fname, const char *line, pubprogfuncs_t *disasmfuncs)
{
static int editorcascade;
console_t *con;
@ -926,7 +926,26 @@ console_t *Con_TextEditor(const char *fname, const char *line, qboolean newfile)
con->close = Con_Editor_Close;
con->maxlines = 0x7fffffff; //line limit is effectively unbounded, for a 31-bit process.
if (!newfile)
if (disasmfuncs)
{
int i;
char buffer[65536];
int start = 1;
int end = INT_MAX;
char *colon = strchr(con->name, ':');
if (colon && *colon==':')
start = strtol(colon+1, &colon, 0);
if (colon && *colon==':')
end = strtol(colon+1, &colon, 0);
for (i = start; !end || i < end; i++)
{
disasmfuncs->GenerateStatementString(disasmfuncs, i, buffer, sizeof(buffer));
if (!*buffer)
break;
Con_PrintCon(con, buffer, PFS_FORCEUTF8|PFS_KEEPMARKUP|PFS_NONOTIFY);
}
}
else
{
file = FS_OpenVFS(fname, "rb", FS_GAME);
if (file)
@ -939,10 +958,9 @@ console_t *Con_TextEditor(const char *fname, const char *line, qboolean newfile)
}
VFS_CLOSE(file);
}
for (l = con->oldest; l; l = l->newer)
Con_Editor_LineChanged(con, l);
}
for (l = con->oldest; l; l = l->newer)
Con_Editor_LineChanged(con, l);
con->display = con->oldest;
con->selstartline = con->selendline = con->oldest; //put the cursor at the start of the file
@ -972,10 +990,10 @@ void Con_TextEditor_f(void)
Con_Printf("%s [filename[:line]]: edit a file\n", Cmd_Argv(0));
return;
}
Con_TextEditor(fname, line, false);
Con_TextEditor(fname, line, NULL);
}
int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *statement, char *reason, pbool fatal)
int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *statement, int firststatement, char *reason, pbool fatal)
{
char newname[MAX_QPATH];
console_t *edit;
@ -983,7 +1001,7 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st
if (!strncmp(filename, "./", 2))
filename+=2;
stepasm = !line || *line < 0;
stepasm = !line || *line < 0 || pr_debugger.ival==2;
//we can cope with no line info by displaying asm
if (editormodal || (stepasm && !statement))
@ -1001,7 +1019,7 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st
return DEBUG_TRACE_OFF; //get lost
}
if (qrenderer == QR_NONE || stepasm)
if (qrenderer == QR_NONE)// || stepasm)
{ //just dump the line of code that's being execed onto the console.
int i;
char buffer[8192];
@ -1087,20 +1105,32 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st
if (stepasm)
{
if (fatal)
return DEBUG_TRACE_ABORT;
return DEBUG_TRACE_OFF; //whoops
if (*statement)
{
char *fname = va(":%#x:%#x", firststatement, firststatement+300);
edit = Con_TextEditor(fname, NULL, prfncs);
if (!edit)
return DEBUG_TRACE_OFF;
firststatement--; //displayed statements are +1
executionlinenum = *statement - firststatement;
Con_Editor_GoToLine(edit, executionlinenum);
}
else
{
if (fatal)
return DEBUG_TRACE_ABORT;
return DEBUG_TRACE_OFF; //whoops
}
}
else
{
edit = Con_TextEditor(filename, NULL, false);
edit = Con_TextEditor(filename, NULL, NULL);
if (!edit)
return DEBUG_TRACE_OFF;
Con_Editor_GoToLine(edit, *line);
executionlinenum = *line;
}
executionlinenum = *line;
{
double oldrealtime = realtime;
@ -1138,7 +1168,7 @@ int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *st
{
if (line)
*line = 0;
*statement = executionlinenum;
*statement = executionlinenum+firststatement;
}
else if (line)
*line = executionlinenum;

View File

@ -862,7 +862,7 @@ void R_LightArrays(const entity_t *entity, vecV_t *coords, avec4_t *colours, int
//don't include world lights
for (lno = rtlights_first; lno < RTL_FIRST; lno++)
{
if (cl_dlights[lno].radius)
if (cl_dlights[lno].radius && (cl_dlights[lno].flags & LFLAG_LIGHTMAP))
{
VectorSubtract (cl_dlights[lno].origin,
entity->origin,
@ -3341,6 +3341,7 @@ static void *Q1MDL_LoadSkins_SV (galiasinfo_t *galias, dmdl_t *pq1inmodel, dalia
}
#ifndef SERVERONLY
static cvar_t dpcompat_nofloodfill = CVARD("dpcompat_nofloodfill", "0", "Disables the q1mdl floodfill. Setting this to 1 may result in blue seams on the vanilla quake models.");
/*
=================
Mod_FloodFillSkin
@ -3377,6 +3378,9 @@ static void Mod_FloodFillSkin( qbyte *skin, int skinwidth, int skinheight )
int filledcolor = -1;
int i;
if (dpcompat_nofloodfill.ival)
return;
if (filledcolor == -1)
{
filledcolor = 0;
@ -8541,6 +8545,9 @@ static qboolean QDECL Mod_LoadCompositeAnim(model_t *mod, void *buffer, size_t f
void Alias_Register(void)
{
#ifdef MD1MODELS
#ifndef SERVERONLY
Cvar_Register(&dpcompat_nofloodfill, NULL);
#endif
Mod_RegisterModelFormatMagic(NULL, "Quake1 Model (mdl)", IDPOLYHEADER, Mod_LoadQ1Model);
Mod_RegisterModelFormatMagic(NULL, "QuakeForge 16bit Model", (('6'<<24)+('1'<<16)+('D'<<8)+'M'), Mod_LoadQ1Model);
#ifdef HEXEN2

View File

@ -89,9 +89,15 @@ cvar_t r_meshpitch;
//#define ODE_DYNAMIC 1
//#endif
//ODE's headers provide version info only as a string, so we don' know when things are deprecated or not.
//this then fucks us over when we try using -Werror
//so until ODE changes its ways, we'll just have to make assumptions and ignore those warnings.
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#define ODEVERSION MAKE2VER(0,15)
#define MAKE2VER(maj,min) (((maj)<<8)|(min))
// LordHavoc: this large chunk of definitions comes from the ODE library
// include files.
#ifdef ODE_STATIC
#undef ODE_DYNAMIC
#define dDOUBLE
@ -1674,9 +1680,17 @@ static void World_ODE_Frame_JointFromEntity(world_t *world, wedict_t *ed)
dJointSetUniversalParam(j, dParamVel2, Vel);
break;
case JOINTTYPE_HINGE2:
dJointSetHinge2Anchor(j, origin[0], origin[1], origin[2]);
dJointSetHinge2Anchor(j, origin[0], origin[1], origin[2]);
#if ODEVERSION>=MAKE2VER(0,16)
{
dReal a1[]={forward[0], forward[1], forward[2]}, a2[]={velocity[0], velocity[1], velocity[2]};
dJointSetHinge2Axes(j, a1, a2);
}
#else
dJointSetHinge2Axis1(j, forward[0], forward[1], forward[2]);
dJointSetHinge2Axis2(j, velocity[0], velocity[1], velocity[2]);
#endif
dJointSetHinge2Param(j, dParamFMax, FMax);
dJointSetHinge2Param(j, dParamHiStop, Stop);
dJointSetHinge2Param(j, dParamLoStop, -Stop);
@ -1953,8 +1967,15 @@ static void QDECL World_ODE_RagCreateJoint(world_t *world, rbejoint_t *joint, rb
break;
case JOINTTYPE_HINGE2:
dJointSetHinge2Anchor(joint->joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]);
#if ODEVERSION>=MAKE2VER(0,16)
{
dReal a1[]={aaa2[1][0], aaa2[1][1], aaa2[1][2]}, a2[]={aaa2[2][0], aaa2[2][1], aaa2[2][2]};
dJointSetHinge2Axes(joint->joint, a1, a2);
}
#else
dJointSetHinge2Axis1(joint->joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]);
dJointSetHinge2Axis2(joint->joint, aaa2[2][0], aaa2[2][1], aaa2[2][2]);
#endif
dJointSetHinge2Param(joint->joint, dParamFMax, info->FMax);
dJointSetHinge2Param(joint->joint, dParamHiStop, info->HiStop);
dJointSetHinge2Param(joint->joint, dParamLoStop, info->LoStop);

View File

@ -90,7 +90,7 @@
#define IMAGEFMT_PKM //file format generally written by etcpack or android's etc1tool. doesn't support mips.
#define IMAGEFMT_DDS //.dds files embed mipmaps and texture compression. faster to load.
//#define IMAGEFMT_BLP //legacy crap
#define IMAGEFMT_BMP //windows bmp. yuck.
#define IMAGEFMT_BMP //windows bmp. yuck. also includes .ico for the luls
#define IMAGEFMT_PCX //paletted junk. required for qw player skins, q2 and a few old skyboxes.
//#define IMAGEFMT_VTF //hl2 image format
#define AVAIL_PNGLIB //.png image format support (read+screenshots)

View File

@ -246,7 +246,7 @@ typedef struct {
qboolean (*ParticleQuery) (int type, int body, char *outstr, int outstrlen);
int (*RunParticleEffectTypeString) (vec3_t org, vec3_t dir, float count, char *name);
int (*ParticleTrail) (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk);
int (*ParticleTrail) (vec3_t startpos, vec3_t end, int type, float timeinterval, int dlkey, vec3_t dlaxis[3], trailstate_t **tsk);
int (*RunParticleEffectState) (vec3_t org, vec3_t dir, float count, int typenum, trailstate_t **tsk);
void (*RunParticleWeather) (vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, char *efname);
void (*RunParticleCube) (int typenum, vec3_t minb, vec3_t maxb, vec3_t dir_min, vec3_t dir_max, float count, int colour, qboolean gravity, float jitter); //typenum may be P_INVALID
@ -256,7 +256,7 @@ typedef struct {
void (*RunParticleEffect4) (vec3_t org, float radius, int color, int effect, int count);
void (*RunParticleEffectPalette) (const char *nameprefix, vec3_t org, vec3_t dir, int color, int count);
void (*ParticleTrailIndex) (vec3_t start, vec3_t end, int type, int color, int crnd, trailstate_t **tsk); //P_INVALID is fine for the type here, you'll get a default trail.
void (*ParticleTrailIndex) (vec3_t start, vec3_t end, int type, float timeinterval, int color, int crnd, trailstate_t **tsk); //P_INVALID is fine for the type here, you'll get a default trail.
qboolean (*InitParticles) (void);
void (*ShutdownParticles) (void);
void (*DelinkTrailstate) (trailstate_t **tsk);

View File

@ -186,7 +186,7 @@ static int debuggerstacky;
void INS_UpdateGrabs(int fullscreen, int activeapp);
#endif
int QCLibEditor(pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *error, pbool fatal);
int QCLibEditor(pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, int firststatement, char *error, pbool fatal);
void QCLoadBreakpoints(const char *vmname, const char *progsname)
{ //this asks the gui to reapply any active breakpoints and waits for them so that any spawn functions can be breakpointed properly.
extern int isPlugin;
@ -377,7 +377,7 @@ qboolean QCExternalDebuggerCommand(char *text)
return true;
}
int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *reason, pbool fatal)
int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, int firststatement, char *reason, pbool fatal)
{
//#if defined(_WIN32) && !defined(FTE_SDL) && !defined(_XBOX)
if (isPlugin >= 2)
@ -474,7 +474,7 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
//#endif
#ifdef TEXTEDITOR
return QCLibEditor(prinst, filename, line, statement, reason, fatal);
return QCLibEditor(prinst, filename, line, statement, firststatement, reason, fatal);
#else
if (fatal)
return DEBUG_TRACE_ABORT;

View File

@ -517,7 +517,7 @@ void QCBUILTIN PF_gettime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
void QCBUILTIN PF_whichpack (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *reason, pbool fatal);
int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, int firststatement, char *reason, pbool fatal);
void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored);
void PR_Common_SaveGame(vfsfile_t *f, pubprogfuncs_t *prinst, qboolean binary);
qboolean PR_Common_LoadGame(pubprogfuncs_t *prinst, char *command, const char **file);

View File

@ -67,7 +67,7 @@ qboolean UI_OpenMenu(void);
void UI_Restart_f(void);
qboolean UI_Q2LayoutChanged(void);
void UI_StringChanged(int num);
qboolean UI_MousePosition(int xpos, int ypos);
qboolean UI_MousePosition(float xpos, float ypos);
int UI_MenuState(void);
qboolean UI_KeyPress(int key, int unicode, qboolean down);
void UI_Reset(void);

View File

@ -141,6 +141,8 @@ void R_NetGraph (void)
M_DrawTextBox (x, y, NET_TIMINGS/8, (NET_GRAPHHEIGHT + textheight)/8);
x = 8;
if (r_netgraph.ival > 1)
CL_ShowTrafficUsage(x + NET_TIMINGS + 8, y);
y += 8; //top border
graphtop = y+textheight;

View File

@ -3490,28 +3490,34 @@ static void X_StoreIcon(Window wnd)
if (!filedata)
filedata = FS_LoadMallocFile("icon.jpg", &filesize);
#endif
#ifdef IMAGEFMT_BMP
if (!filedata)
filedata = FS_LoadMallocFile("icon.ico", &filesize);
#endif
if (filedata)
{
int imagewidth, imageheight;
int *iconblob;
unsigned long *iconblob; //yes, long, even on 64bit machines. and even when we claim it to be 32bit. xlib legacy cruft that'll get stripped...
uploadfmt_t format;
qbyte *imagedata = ReadRawImageFile(filedata, filesize, &imagewidth, &imageheight, &format, true, "icon.png");
Z_Free(filedata);
iconblob = BZ_Malloc(sizeof(int)*(2+imagewidth*imageheight));
iconblob[0] = imagewidth;
iconblob[1] = imageheight;
//needs to be 0xARGB, rather than RGBA bytes
for (i = 0; i < imagewidth*imageheight; i++)
iconblob[i+2] = (imagedata[i*4+3]<<24) | (imagedata[i*4+0]<<16) | (imagedata[i*4+1]<<8) | (imagedata[i*4+2]<<0);
Z_Free(imagedata);
if (imagedata)
{
iconblob = BZ_Malloc(sizeof(*iconblob)*(2+imagewidth*imageheight));
iconblob[0] = imagewidth;
iconblob[1] = imageheight;
//needs to be 0xARGB, rather than RGBA bytes
for (i = 0; i < imagewidth*imageheight; i++)
iconblob[i+2] = (imagedata[i*4+3]<<24) | (imagedata[i*4+0]<<16) | (imagedata[i*4+1]<<8) | (imagedata[i*4+2]<<0);
Z_Free(imagedata);
x11.pXChangeProperty(vid_dpy, wnd, propname, proptype, 32, PropModeReplace, (void*)iconblob, 2+imagewidth*imageheight);
BZ_Free(iconblob);
x11.pXChangeProperty(vid_dpy, wnd, propname, proptype, 32, PropModeReplace, (void*)iconblob, 2+imagewidth*imageheight);
BZ_Free(iconblob);
return;
}
}
else
{
//fall back to the embedded icon.
unsigned long data[64*64+2];

View File

@ -429,7 +429,6 @@ r_part te_teleport
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D s_t0;
void main(void)
{
vec2 nst;

View File

@ -180,6 +180,8 @@ void PDECL PR_GenerateStatementString (pubprogfuncs_t *ppf, int statementnum, ch
*out = 0;
outlen--;
if ((unsigned)statementnum >= current_progstate->progs->numstatements)
return;
switch(current_progstate->structtype)
{
case PST_DEFAULT:
@ -1364,7 +1366,7 @@ static const char *lastfile = NULL;
lastfile = file;
faultline = lastline;
debugaction = externs->useeditor(&progfuncs->funcs, lastfile, ((lastline!=-1)?&lastline:NULL), &statement, fault, fatal);
debugaction = externs->useeditor(&progfuncs->funcs, lastfile, ((lastline!=-1)?&lastline:NULL), &statement, f->first_statement, fault, fatal);
// if (pn != prinst.pr_typecurrent)

View File

@ -230,7 +230,7 @@ typedef struct progexterns_s {
void *(VARGS *memalloc) (int size); //small string allocation malloced and freed randomly by the executor. (use malloc if you want)
void (VARGS *memfree) (void * mem);
int (PDECL *useeditor) (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *reason, pbool fatal); //called on syntax errors or step-by-step debugging. line and statement(if line was set to 0) can be used to change the next line. return value is the new debug state to use/step.
int (PDECL *useeditor) (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, int funcstart, char *reason, pbool fatal); //called on syntax errors or step-by-step debugging. line and statement(if line was set to 0) can be used to change the next line. return value is the new debug state to use/step.
void (PDECL *addressablerelocated) (pubprogfuncs_t *progfuncs, char *oldb, char *newb, int oldlen); //called when the progs memory was resized. you must fix up all pointers to globals, strings, fields, addressable blocks.
builtin_t *globalbuiltins; //these are available to all progs

View File

@ -562,7 +562,7 @@ public:
s->SendScintilla(QsciScintillaBase::SCI_STYLESETBACK, QsciScintillaBase::STYLE_BRACEBAD, QColor(0xff, 0xaf, 0xaf));
//SCE_C_WORD
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, static_cast<int>(0),
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 0ul,
"if else for do not while asm break case const continue "
"default enum enumflags extern "
"float goto __in __out __inout noref "
@ -578,11 +578,11 @@ public:
{
char buffer[65536];
GenBuiltinsList(buffer, sizeof(buffer));
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 1, buffer);
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 1ul, buffer);
}
//SCE_C_COMMENTDOCKEYWORDERROR
//SCE_C_GLOBALCLASS
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 3,
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 3ul,
""
);
//preprocessor listing
@ -590,11 +590,11 @@ public:
char *deflist = QCC_PR_GetDefinesList();
if (!deflist)
deflist = strdup("");
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 4, deflist);
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 4ul, deflist);
free(deflist);
}
//task markers (in comments only)
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 5,
s->SendScintilla(QsciScintillaBase::SCI_SETKEYWORDS, 5ul,
"TODO FIXME BUG"
);

View File

@ -202,6 +202,9 @@ typedef struct botlib_import_s
//
int (QDECL *DebugPolygonCreate)(int color, int numPoints, vec3_t *points);
void (QDECL *DebugPolygonDelete)(int id);
//FTE additions...
void (QDECL *Error)(const char *error);
} botlib_import_t;
typedef struct aas_export_s

View File

@ -10874,7 +10874,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//312
//313
//2d (immediate) operations
{"drawtextfield", PF_Fixme, 0, 0, 0, 0/*314*/, D("void(vector pos, vector size, float alignflags, string text)", "Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3.")},// (EXT_CSQC)
{"drawtextfield", PF_Fixme, 0, 0, 0, 0/*314*/, D("float(vector pos, vector size, float alignflags, string text)", "Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3. Returns the total number of lines.")},// (EXT_CSQC)
{"drawline", PF_Fixme, 0, 0, 0, 315, D("void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional float drawflag)", "Draws a 2d line between the two 2d points.")},// (EXT_CSQC)
{"iscachedpic", PF_Fixme, 0, 0, 0, 316, D("float(string name)", "Checks to see if the image is currently loaded. Engines might lie, or cache between maps.")},// (EXT_CSQC)
{"precache_pic", PF_Fixme, 0, 0, 0, 317, D("string(string name, optional float trywad)", "Forces the engine to load the named image. If trywad is specified, the specified name must any lack path and extension.")},// (EXT_CSQC)

View File

@ -1772,19 +1772,49 @@ qboolean SV_Loadgame (const char *unsafe_savename)
#ifndef QUAKETC
{"%s.sav"},
#endif
{"%s"}
};
int bd,best;
int bestd=0x7fffffff,best=0;
time_t bestt=0,t;
Q_strncpyz(savename, unsafe_savename, sizeof(savename));
if (!*savename || strstr(savename, ".."))
strcpy(savename, "quick");
{ //if no args, or its invalid, try to pick the last one that was saved (of those listed in the menu)
size_t n;
static char *autoload[] = { "quick", "a0", "a1", "a2",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9"};
strcpy(savename, "quick"); //default...
for (len = 0, bd=0x7fffffff,best=0; len < countof(savefiles); len++)
{
int d = FS_FLocateFile(va(savefiles[len].pattern, savename), FSLF_DONTREFERENCE|FSLF_DEEPONFAILURE, &savefiles[len].loc);
if (bd > d)
for (n = 0; n < countof(autoload); n++)
{
bd = d;
for (len = 0; len < countof(savefiles)-1; len++)
{
int d = FS_FLocateFile(va(savefiles[len].pattern, autoload[n]), FSLF_DONTREFERENCE, &savefiles[len].loc);
if (!d)
continue;
FS_GetLocMTime(&savefiles[len].loc, &t);
if (d < bestd || (bestd==d&&t>bestt))
{
bestd = d;
bestt = t;
best = len;
strcpy(savename, autoload[n]);
}
}
}
}
for (len = 0; len < countof(savefiles); len++)
{
int d = FS_FLocateFile(va(savefiles[len].pattern, savename), FSLF_DONTREFERENCE, &savefiles[len].loc);
if (!d)
continue;
FS_GetLocMTime(&savefiles[len].loc, &t);
if (d < bestd || (bestd==d&&t>bestt))
{
bestd = d;
bestt = t;
best = len;
}
}

View File

@ -576,12 +576,14 @@ typedef struct client_s
#ifdef Q3SERVER
int gamestatesequence; //the sequence number the initial gamestate was sent in.
int last_server_command_num;
int last_client_command_num;
int num_server_commands;
int num_client_commands;
char server_commands[64][1024];
char last_client_command[1024];
//quake3 does reliables only via this mechanism. basically just like q1's stuffcmds.
int server_command_ack; //number known to have been received.
int server_command_sequence; //number available.
char server_commands[64][1024]; //the commands, to deal with resends
#endif
//true/false/persist

View File

@ -779,11 +779,13 @@ void SV_Map_f (void)
// gametype->callback = gtcallback;
/* map_restart doesn't need to handle gametype changes - eukara */
if (Q_strcasecmp(Cmd_Argv(0), "map_restart"))
if (!isrestart)
{
if (q3singleplayer)
Cvar_ForceSet(gametype, "2");//singleplayer
else if (gametype->value == 2)
Cvar_ForceSet(gametype, "");//force to ffa deathmatch
}
}
#endif

View File

@ -1480,81 +1480,84 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb
outno = 0;
outmax = frame->maxresend;
/*start writing the packet*/
MSG_WriteByte (msg, svcfte_updateentities);
if (ISNQCLIENT(client) && (client->fteprotocolextensions2 & PEXT2_PREDINFO))
if (msg->cursize + 52 <= msg->maxsize)
{
MSG_WriteShort(msg, client->last_sequence&0xffff);
}
// Con_Printf("Gen sequence %i\n", sequence);
MSG_WriteFloat(msg, sv.world.physicstime);
if (client->pendingdeltabits[0] & UF_REMOVE)
{
SV_EmitDeltaEntIndex(msg, 0, true, true);
resend[outno].bits = UF_REMOVE;
resend[outno].flags = 0;
resend[outno++].entnum = 0;
client->pendingdeltabits[0] &= ~UF_REMOVE;
}
for(j = 1; j < client->sentents.num_entities; j++)
{
bits = client->pendingdeltabits[j];
if (!(bits & ~UF_RESET2)) //skip while there's nothing to send (skip reset2 if there's no other changes, its only to reduce chances of the client getting 'new' entities containing just an origin)*/
continue;
if (msg->cursize + 50 > msg->maxsize)
/*start writing the packet*/
MSG_WriteByte (msg, svcfte_updateentities);
if (ISNQCLIENT(client) && (client->fteprotocolextensions2 & PEXT2_PREDINFO))
{
overflow = true;
break; /*give up if it gets full. FIXME: bone data is HUGE.*/
}
if (outno >= outmax)
{ //expand the frames. may need some copying...
SV_ExpandNackFrames(client, outno+1);
break;
MSG_WriteShort(msg, client->last_sequence&0xffff);
}
// Con_Printf("Gen sequence %i\n", sequence);
MSG_WriteFloat(msg, sv.world.physicstime);
if (bits & UF_REMOVE)
{ //if reset is set, then reset was set eroneously.
SV_EmitDeltaEntIndex(msg, j, true, true);
if (client->pendingdeltabits[0] & UF_REMOVE)
{
SV_EmitDeltaEntIndex(msg, 0, true, true);
resend[outno].bits = UF_REMOVE;
// Con_Printf("REMOVE %i @ %i\n", j, sequence);
resend[outno].flags = 0;
resend[outno++].entnum = 0;
client->pendingdeltabits[0] &= ~UF_REMOVE;
}
else if (client->sentents.entities[j].number) /*only send a new copy of the ent if they actually have one already*/
for(j = 1; j < client->sentents.num_entities; j++)
{
//if we didn't reach the end in the last packet, start at that point to avoid spam
//player slots are exempt from this, so they are in every packet (strictly speaking only the local player 'needs' this, but its nice to have it for high-priority targets too)
if (j < client->nextdeltaindex && j > svs.allocated_client_slots)
bits = client->pendingdeltabits[j];
if (!(bits & ~UF_RESET2)) //skip while there's nothing to send (skip reset2 if there's no other changes, its only to reduce chances of the client getting 'new' entities containing just an origin)*/
continue;
if (bits & UF_RESET2)
if (msg->cursize + 52 > msg->maxsize)
{
/*if reset2, then this is the second packet sent to the client and should have a forced reset (but which isn't tracked)*/
resend[outno].bits = bits & ~UF_RESET2;
bits = UF_RESET | SVFTE_DeltaCalcBits(&EDICT_NUM_PB(svprogfuncs, j)->baseline, NULL, &client->sentents.entities[j], client->sentents.bonedata);
// Con_Printf("RESET2 %i @ %i\n", j, sequence);
overflow = true;
break; /*give up if it gets full. FIXME: bone data is HUGE.*/
}
else if (bits & UF_RESET)
{
/*flag the entity for the next packet, so we always get two resets when it appears, to reduce the effects of packetloss on seeing rockets etc*/
client->pendingdeltabits[j] = UF_RESET2;
bits = UF_RESET | SVFTE_DeltaCalcBits(&EDICT_NUM_PB(svprogfuncs, j)->baseline, NULL, &client->sentents.entities[j], client->sentents.bonedata);
resend[outno].bits = UF_RESET;
// Con_Printf("RESET %i @ %i\n", j, sequence);
if (outno >= outmax)
{ //expand the frames. may need some copying...
SV_ExpandNackFrames(client, outno+1);
break;
}
else
resend[outno].bits = bits;
SV_EmitDeltaEntIndex(msg, j, false, true);
SVFTE_WriteUpdate(bits, &client->sentents.entities[j], msg, client->fteprotocolextensions2, client->sentents.bonedata);
if (bits & UF_REMOVE)
{ //if reset is set, then reset was set eroneously.
SV_EmitDeltaEntIndex(msg, j, true, true);
resend[outno].bits = UF_REMOVE;
// Con_Printf("REMOVE %i @ %i\n", j, sequence);
}
else if (client->sentents.entities[j].number) /*only send a new copy of the ent if they actually have one already*/
{
//if we didn't reach the end in the last packet, start at that point to avoid spam
//player slots are exempt from this, so they are in every packet (strictly speaking only the local player 'needs' this, but its nice to have it for high-priority targets too)
if (j < client->nextdeltaindex && j > svs.allocated_client_slots)
continue;
if (bits & UF_RESET2)
{
/*if reset2, then this is the second packet sent to the client and should have a forced reset (but which isn't tracked)*/
resend[outno].bits = bits & ~UF_RESET2;
bits = UF_RESET | SVFTE_DeltaCalcBits(&EDICT_NUM_PB(svprogfuncs, j)->baseline, NULL, &client->sentents.entities[j], client->sentents.bonedata);
// Con_Printf("RESET2 %i @ %i\n", j, sequence);
}
else if (bits & UF_RESET)
{
/*flag the entity for the next packet, so we always get two resets when it appears, to reduce the effects of packetloss on seeing rockets etc*/
client->pendingdeltabits[j] = UF_RESET2;
bits = UF_RESET | SVFTE_DeltaCalcBits(&EDICT_NUM_PB(svprogfuncs, j)->baseline, NULL, &client->sentents.entities[j], client->sentents.bonedata);
resend[outno].bits = UF_RESET;
// Con_Printf("RESET %i @ %i\n", j, sequence);
}
else
resend[outno].bits = bits;
SV_EmitDeltaEntIndex(msg, j, false, true);
SVFTE_WriteUpdate(bits, &client->sentents.entities[j], msg, client->fteprotocolextensions2, client->sentents.bonedata);
}
client->pendingdeltabits[j] = 0;
resend[outno].flags = 0;
resend[outno++].entnum = j;
}
client->pendingdeltabits[j] = 0;
resend[outno].flags = 0;
resend[outno++].entnum = j;
MSG_WriteShort(msg, 0);
}
MSG_WriteShort(msg, 0);
if (j == client->sentents.num_entities) //looks like we sent them all
client->nextdeltaindex = 0; //start afresh with the next packet.

View File

@ -61,6 +61,7 @@ cvar_t sv_gameplayfix_bouncedownslopes = CVARD( "sv_gameplayfix_grenadebouncedo
#if !defined(CLIENTONLY) && defined(NQPROT) && !defined(NOLEGACY)
cvar_t sv_gameplayfix_spawnbeforethinks = CVARD( "sv_gameplayfix_spawnbeforethinks", "0", "Fixes an issue where player thinks (including Pre+Post) can be called before PutClientInServer. Unfortunately at least one mod depends upon PreThink being called first in order to correctly determine spawn positions.");
#endif
cvar_t dpcompat_noretouchground = CVARD( "dpcompat_noretouchground", "0", "Prevents entities that are already standing on an entity from touching the same entity again.");
cvar_t sv_sound_watersplash = CVAR( "sv_sound_watersplash", "misc/h2ohit1.wav");
cvar_t sv_sound_land = CVAR( "sv_sound_land", "demon/dland2.wav");
cvar_t sv_stepheight = CVARAFD("pm_stepheight", "", "sv_stepheight", CVAR_SERVERINFO, "If empty, the value "STRINGIFY(PM_DEFAULTSTEPHEIGHT)" will be used instead. This is the size of the step you can step up or down.");
@ -98,6 +99,7 @@ void WPhys_Init(void)
Cvar_Register (&sv_gameplayfix_multiplethinks, cvargroup_serverphysics);
Cvar_Register (&sv_gameplayfix_stepdown, cvargroup_serverphysics);
Cvar_Register (&sv_gameplayfix_bouncedownslopes, cvargroup_serverphysics);
Cvar_Register (&dpcompat_noretouchground, cvargroup_serverphysics);
#if !defined(CLIENTONLY) && defined(NQPROT) && !defined(NOLEGACY)
Cvar_Register (&sv_gameplayfix_spawnbeforethinks, cvargroup_serverphysics);
@ -450,6 +452,12 @@ static int WPhys_FlyMove (world_t *w, wedict_t *ent, const vec3_t gravitydir, fl
if (!trace.ent)
Host_Error ("SV_FlyMove: !trace.ent");
if (dpcompat_noretouchground.ival)
{ //note: also sets onground AFTER the touch event.
if (!((int)ent->v->flags&FL_ONGROUND) || ent->v->groundentity!=EDICT_TO_PROG(w->progs, trace.ent))
WPhys_Impact (w, ent, &trace);
}
if (-DotProduct(gravitydir, trace.plane.normal) > 0.7)
{
blocked |= 1; // floor
@ -469,7 +477,8 @@ static int WPhys_FlyMove (world_t *w, wedict_t *ent, const vec3_t gravitydir, fl
//
// run the impact function
//
WPhys_Impact (w, ent, &trace);
if (!dpcompat_noretouchground.ival)
WPhys_Impact (w, ent, &trace);
if (ED_ISFREE(ent))
break; // removed by the impact function

View File

@ -2566,7 +2566,12 @@ qboolean SV_SendClientDatagram (client_t *client)
}
if (client->netchan.fragmentsize)
clientlimit = client->netchan.fragmentsize; //try not to overflow
{
if (client->netchan.remote_address.type == NA_LOOPBACK)
clientlimit = countof(buf); //biiiig...
else
clientlimit = client->netchan.fragmentsize; //try not to overflow
}
else if (client->protocol == SCP_NETQUAKE)
clientlimit = MAX_NQDATAGRAM; //vanilla client is limited.
else
@ -2574,6 +2579,8 @@ qboolean SV_SendClientDatagram (client_t *client)
if (clientlimit > countof(buf))
clientlimit = countof(buf);
msg.maxsize = clientlimit - client->datagram.cursize;
if (msg.maxsize <= 0)
msg.maxsize = clientlimit; //its going to overflow. favour ents over unreliables. its a little less fatal
if (sv.world.worldmodel && !client->controller)
{

View File

@ -34,6 +34,9 @@ static botlib_export_t *FTE_GetBotLibAPI(int apiVersion, botlib_import_t *import
{(void**)&pGetBotLibAPI, "GetBotLibAPI"},
{NULL}
};
if (!botlib && host_parms.binarydir)
botlib = Sys_LoadLibrary(va("%slibfteq3bot", host_parms.binarydir), funcs);
if (!botlib)
botlib = Sys_LoadLibrary("botlib", funcs);
if (!botlib)
@ -764,8 +767,8 @@ void SVQ3_SendServerCommand(client_t *cl, char *str)
return;
}
cl->num_server_commands++;
Q_strncpyz(cl->server_commands[cl->num_server_commands & TEXTCMD_MASK], str, sizeof(cl->server_commands[0]));
cl->server_command_sequence++;
Q_strncpyz(cl->server_commands[cl->server_command_sequence & TEXTCMD_MASK], str, sizeof(cl->server_commands[0]));
}
void SVQ3_SendConfigString(client_t *dest, int num, char *string)
@ -832,11 +835,11 @@ static int SVQ3_BotGetConsoleMessage( int client, char *buf, int size )
cl = &svs.clients[client];
// cl->lastPacketTime = svs.time;
if (cl->last_server_command_num == cl->num_server_commands)
if (cl->server_command_ack == cl->server_command_sequence)
return false;
cl->last_server_command_num++;
index = cl->last_server_command_num & TEXTCMD_MASK;
cl->server_command_ack++;
index = cl->server_command_ack & TEXTCMD_MASK;
if ( !cl->server_commands[index][0] )
return false;
@ -1804,6 +1807,10 @@ static void QDECL BL_DebugLineShow(int line, vec3_t start, vec3_t end, int color
static int QDECL BL_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {return 0;}
static void QDECL BL_DebugPolygonDelete(int id) {}
void QDECL BL_Error(const char *msg)
{
Sys_Error("%s", msg);
}
#endif
static void SV_InitBotLib(void)
@ -1840,6 +1847,8 @@ static void SV_InitBotLib(void)
import.DebugPolygonCreate= BL_DebugPolygonCreate;
import.DebugPolygonDelete = BL_DebugPolygonDelete;
import.Error = BL_Error;
// Z_FreeTags(Z_TAG_BOTLIB);
botlibmemoryavailable = 1024*1024*16;
if (bot_enable->value)
@ -2690,6 +2699,23 @@ static void SVQ3Q1_SendGamestateConfigstrings(sizebuf_t *msg)
}
#endif
static void SVQ3_WriteServerCommandsToClient(client_t *client, sizebuf_t *msg)
{
int i;
int j, len;
char *str;
for(i=client->server_command_ack+1; i<=client->server_command_sequence; i++)
{
MSG_WriteBits(msg, svcq3_serverCommand, 8);
MSG_WriteBits(msg, i, 32);
str = client->server_commands[i & TEXTCMD_MASK];
len = strlen(str);
for (j = 0; j <= len; j++)
MSG_WriteBits(msg, str[j], 8);
}
}
//writes initial gamestate
void SVQ3_SendGameState(client_t *client)
{
@ -2709,8 +2735,10 @@ void SVQ3_SendGameState(client_t *client)
// write last clientCommand number we have processed
MSG_WriteBits(&msg, client->last_client_command_num, 32);
SVQ3_WriteServerCommandsToClient(client, &msg);
MSG_WriteBits(&msg, svcq3_gamestate, 8 );
MSG_WriteBits(&msg, client->num_client_commands, 32);
MSG_WriteBits(&msg, client->server_command_sequence, 32);
switch (svs.gametype)
{
@ -2781,23 +2809,6 @@ void SVQ3_SendGameState(client_t *client)
client->gamestatesequence = client->last_sequence;
}
void SVQ3_WriteServerCommandsToClient(client_t *client, sizebuf_t *msg)
{
int i;
int j, len;
char *str;
for(i=client->last_server_command_num+1; i<=client->num_server_commands; i++)
{
MSG_WriteBits(msg, svcq3_serverCommand, 8);
MSG_WriteBits(msg, i, 32);
str = client->server_commands[i & TEXTCMD_MASK];
len = strlen(str);
for (j = 0; j <= len; j++)
MSG_WriteBits(msg, str[j], 8);
}
}
void SVQ3_SendMessage(client_t *client)
{
qbyte buffer[MAX_OVERALLMSGLEN];
@ -2992,7 +3003,7 @@ void SVQ3_ParseUsercmd(client_t *client, qboolean delta)
return; // was dropped
// calculate key for usercmd decryption
string = client->server_commands[client->last_server_command_num & TEXTCMD_MASK];
string = client->server_commands[client->server_command_ack & TEXTCMD_MASK];
key = client->last_sequence ^ fs_key ^ StringKey(string, 32);
// read delta sequenced usercmds
@ -3207,11 +3218,11 @@ void SVQ3_ParseClientMessage(client_t *client)
}
// read last server command number client received
client->last_server_command_num = MSG_ReadBits(32);
if( client->last_server_command_num <= client->num_server_commands - TEXTCMD_BACKUP )
client->last_server_command_num = client->num_server_commands - TEXTCMD_BACKUP + 1;
else if( client->last_server_command_num > client->num_server_commands )
client->last_server_command_num = client->num_server_commands;
client->server_command_ack = MSG_ReadBits(32);
if( client->server_command_ack <= client->server_command_sequence - TEXTCMD_BACKUP )
client->server_command_ack = client->server_command_sequence - TEXTCMD_BACKUP + 1; //too old
else if( client->server_command_ack > client->server_command_sequence )
client->server_command_ack = client->server_command_sequence; //client is from the future? o.O make fatal?
// check if message is from a previous level
if( serverid != svs.spawncount )
@ -3243,7 +3254,7 @@ void SVQ3_ParseClientMessage(client_t *client)
if(msg_readcount > net_message.cursize)
{
Con_Printf("corrupted packet from %s\n", client->name);
Con_Printf("corrupt packet from %s\n", client->name);
client->drop = true;
return;
}
@ -3257,7 +3268,7 @@ void SVQ3_ParseClientMessage(client_t *client)
switch(c)
{
default:
Con_Printf("corrupted packet from %s\n", client->name);
Con_Printf("corrupt packet from %s\n", client->name);
client->drop = true;
return;
case clcq3_nop: