diff --git a/engine/client/cl_cam.c b/engine/client/cl_cam.c index 97900d9b..7aa67cfe 100644 --- a/engine/client/cl_cam.c +++ b/engine/client/cl_cam.c @@ -100,7 +100,7 @@ void Cam_Lock(playerview_t *pv, int playernum) pv->cam_spec_track = playernum; pv->cam_locked = false; - pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); //free floating + pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); //free floating until actually locked Skin_FlushPlayers(); @@ -765,6 +765,7 @@ void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg) pv->cam_auto = CAM_TRACK; Cam_Lock(pv, slot); + //and force the lock here and now pv->cam_locked = true; pv->viewentity = slot+1; } diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index bc0937dc..3b97c666 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -1287,6 +1287,8 @@ void DP5_ParseDelta(entity_state_t *s) s->glowmod[1] = MSG_ReadByte(); s->glowmod[2] = MSG_ReadByte(); } + if (bits & E5_TRAILEFFECTNUM) + s->u.q1.traileffectnum = MSG_ReadShort(); } void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o( diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index dbb71ba8..bd475d8c 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -4406,75 +4406,90 @@ void CL_SetStatString (int pnum, int stat, char *value) CL_MuzzleFlash ============== */ -void CL_MuzzleFlash (int destsplit) +void CL_MuzzleFlash (int entnum) { - vec3_t fv, rv, uv; - dlight_t *dl=NULL; - int i; + dlight_t *dl; player_state_t *pl; packet_entities_t *pack; entity_state_t *s1; int pnum; - + vec3_t org = {0,0,0}; + vec3_t axis[3] = {{0,0,0}}; + int dlightkey = 0; + extern int pt_muzzleflash; extern cvar_t cl_muzzleflash; - i = MSGCL_ReadEntity (); - //was it us? if (!cl_muzzleflash.ival) // remove all muzzleflashes return; - if (i-1 == cl.playerview[destsplit].playernum && cl_muzzleflash.value == 2) + if (cl_muzzleflash.value == 2) + { + //muzzleflash 2 removes muzzleflashes on us + for (pnum = 0; pnum < cl.splitclients; pnum++) + if (entnum-1 == cl.playerview[pnum].playernum) + return; + } + + if (!dlightkey) + { + pack = &cl.inframes[cl.validsequence&UPDATE_MASK].packet_entities; + + for (pnum=0 ; pnumnum_entities ; pnum++) //try looking for an entity with that id first + { + s1 = &pack->entities[pnum]; + + if (s1->number == entnum) + { + dlightkey = entnum; + VectorCopy(s1->origin, org); + AngleVectors(s1->angles, axis[0], axis[1], axis[2]); + break; + } + } + } + if (!dlightkey) + { //that ent number doesn't exist, go for a player with that number + if ((unsigned)(entnum) <= cl.allocated_client_slots && entnum > 0) + { + pl = &cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[entnum-1]; + + if (pl->messagenum == cl.validsequence) + { + dlightkey = -entnum; + VectorCopy(pl->origin, org); + AngleVectors(pl->viewangles, axis[0], axis[1], axis[2]); + if (pl->szmins[2] == 0) /*hull is 0-based, so origin is bottom of model, move the light up slightly*/ + org[2] += pl->szmaxs[2]/2; + } + } + } + + if (!dlightkey) return; - pack = &cl.inframes[cl.validsequence&UPDATE_MASK].packet_entities; - - for (pnum=0 ; pnumnum_entities ; pnum++) //try looking for an entity with that id first + if (P_RunParticleEffectType(org, NULL, 1, pt_muzzleflash)) { - s1 = &pack->entities[pnum]; + dl = CL_AllocDlight (dlightkey); + VectorMA (org, 15, axis[0], dl->origin); + memcpy(dl->axis, axis, sizeof(dl->axis)); - if (s1->number == i) - { - dl = CL_AllocDlight (i); - VectorCopy (s1->origin, dl->origin); - AngleVectors(s1->angles, dl->axis[0], dl->axis[1], dl->axis[2]); - break; - } - } - if (pnum==pack->num_entities) - { //that ent number doesn't exist, go for a player with that number - if ((unsigned)(i) <= cl.allocated_client_slots && i > 0) - { - pl = &cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[i-1]; + dl->radius = 200 + (rand()&31); + dl->minlight = 32; + dl->die = cl.time + 0.1; + dl->color[0] = 1.5; + dl->color[1] = 1.3; + dl->color[2] = 1.0; - dl = CL_AllocDlight (-i); - VectorCopy (pl->origin, dl->origin); //set it's origin - if (pl->szmins[2] == 0) /*hull is 0-based, so origin is bottom of model, move the light up slightly*/ - dl->origin[2] += pl->szmaxs[2]/2; - AngleVectors(pl->viewangles, dl->axis[0], dl->axis[1], dl->axis[2]); - - AngleVectors (pl->viewangles, fv, rv, uv); //shift it up a little - VectorMA (dl->origin, 15, fv, dl->origin); - } - else - return; - } - - dl->radius = 200 + (rand()&31); - dl->minlight = 32; - dl->die = cl.time + 0.1; - dl->color[0] = 1.3; - dl->color[1] = 1.3; - dl->color[2] = 1.3; - - dl->channelfade[0] = 1.5; - dl->channelfade[1] = 0.75; - dl->channelfade[2] = 0.375; - dl->decay = 500; + dl->channelfade[0] = 1.5; + dl->channelfade[1] = 0.75; + dl->channelfade[2] = 0.375; + dl->decay = 1000; #ifdef RTLIGHTS - dl->lightcolourscales[2] = 4; + dl->lightcolourscales[2] = 4; #endif + } } #ifdef Q2CLIENT @@ -5761,7 +5776,7 @@ void CLQW_ParseServerMessage (void) break; case svc_muzzleflash: - CL_MuzzleFlash (destsplit); + CL_MuzzleFlash (MSGCL_ReadEntity()); break; case svc_updateuserinfo: diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 2f731cd7..f3c842ea 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -888,6 +888,20 @@ void CL_PredictMovePNum (int seat) VectorCopy (pv->viewangles, pv->simangles); } + if (!pv->cam_locked && pv->cam_auto && cl.spectator && pv->cam_spec_track >= 0 && pv->cam_spec_track < cl.allocated_client_slots && pv->viewentity != pv->cam_spec_track+1) + { + if (cl.inframes[cl.validsequence & UPDATE_MASK].playerstate[pv->cam_spec_track].messagenum == cl.validsequence) + { + pv->cam_locked = true; + pv->viewentity = pv->cam_spec_track+1; + } + else if (pv->cam_spec_track+1 < cl.maxlerpents && cl.lerpents[pv->cam_spec_track+1].sequence == cl.lerpentssequence) + { + pv->cam_locked = true; + pv->viewentity = pv->cam_spec_track+1; + } + } + nopred = cl_nopred.ival; //don't wrap diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 6abb235e..dd6da0ae 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. entity_state_t *CL_FindPacketEntity(int num); int + pt_muzzleflash=P_INVALID, pt_gunshot=P_INVALID, ptdp_gunshotquad=P_INVALID, pt_spike=P_INVALID, @@ -420,6 +421,7 @@ void CL_RegisterParticles(void) } } + pt_muzzleflash = P_FindParticleType("TE_MUZZLEFLASH"); pt_gunshot = P_FindParticleType("TE_GUNSHOT"); /*shotgun*/ ptdp_gunshotquad = P_FindParticleType("TE_GUNSHOTQUAD"); /*DP: quadded shotgun*/ pt_spike = P_FindParticleType("TE_SPIKE"); /*nailgun*/ @@ -770,6 +772,7 @@ void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ n return; } + b->rflags = RF_NOSHADOW; b->entity = ent; b->model = m; b->particleeffect = btype; @@ -858,7 +861,8 @@ void CL_ParseStream (int type) Con_Printf ("beam list overflow!\n"); return; } - + + b->rflags = RF_NOSHADOW; b->entity = ent; b->tag = tag; b->bflags = flags; @@ -914,7 +918,7 @@ void CL_ParseStream (int type) b2->emitstate = NULL; b2->model = Mod_ForName("models/stsunsf2.mdl", MLV_WARN); b2->alpha = 0.5; - b2->rflags = RF_TRANSLUCENT; + b2->rflags = RF_TRANSLUCENT|RF_NOSHADOW; } } //FIXME: we don't add the blob corners+smoke @@ -1742,7 +1746,7 @@ typedef struct custtentinst_s } custtentinst_t; custtentinst_t *activepcusttents; -void CL_SpawnCustomTEnd(custtentinst_t *info) +void CL_SpawnCustomTEnt(custtentinst_t *info) { clcustomtents_t *t = info->type; qboolean failed; @@ -1838,7 +1842,7 @@ void CL_RunPCustomTEnts(void) lasttime = cl.time; for (ef = activepcusttents; ef; ef = ef->next) { - CL_SpawnCustomTEnd(ef); + CL_SpawnCustomTEnt(ef); } } @@ -1960,7 +1964,7 @@ void CL_ParseCustomTEnt(void) } } else - CL_SpawnCustomTEnd(&info); + CL_SpawnCustomTEnt(&info); } void CL_RefreshCustomTEnts(void) { @@ -2024,7 +2028,7 @@ int CL_TranslateParticleFromServer(int qceffect) return cl.particle_csprecache[qceffect]; } else - return -1; + return P_INVALID; // else // { diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 477a5c25..9f961495 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -55,6 +55,7 @@ HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion, static cvar_t in_dinput = CVARF("in_dinput","0", CVAR_ARCHIVE); static cvar_t in_builtinkeymap = CVARF("in_builtinkeymap", "0", CVAR_ARCHIVE); static cvar_t in_simulatemultitouch = CVAR("in_simulatemultitouch", "0"); +static cvar_t in_nonstandarddeadkeys = CVARD("in_nonstandarddeadkeys", "1", "Discard input events that result in multiple keys. Only the last key will be used. This results in behaviour that differs from eg notepad. To use a dead key, press it twice instead of the dead key followed by space."); static cvar_t m_accel_noforce = CVAR("m_accel_noforce", "0"); static cvar_t m_threshold_noforce = CVAR("m_threshold_noforce", "0"); @@ -1095,6 +1096,7 @@ void INS_Init (void) Cvar_Register (&in_dinput, "Input Controls"); Cvar_Register (&in_builtinkeymap, "Input Controls"); + Cvar_Register (&in_nonstandarddeadkeys, "Input Controls"); Cvar_Register (&in_simulatemultitouch, "Input Controls"); Cvar_Register (&m_accel_noforce, "Input Controls"); @@ -2086,6 +2088,7 @@ void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdev extern cvar_t in_builtinkeymap; int qcode; int unicode; + int chars; extern int keyshift[256]; extern int shift_down; @@ -2096,11 +2099,16 @@ void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdev BYTE keystate[256]; WCHAR wchars[2]; GetKeyboardState(keystate); - if (ToUnicode(wParam, HIWORD(lParam), keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0) + chars = ToUnicode(wParam, HIWORD(lParam), keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0); + + if (chars > 0) { - //ignore if more, its probably a compose and > 65535 anyway. we can't represent that. -// if (!wchars[1]) - unicode = wchars[0]; + if (!in_nonstandarddeadkeys.ival) + { + for (unicode = 0; unicode < chars-1; unicode++) + Key_Event (qdeviceid, 0, wchars[unicode], down); + } + unicode = wchars[chars-1]; } else unicode = 0; } @@ -2110,7 +2118,6 @@ void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdev if (shift_down && unicode < K_MAX && keyshift[unicode]) unicode = keyshift[unicode]; } - Key_Event (qdeviceid, qcode, unicode, down); } #endif diff --git a/engine/client/keys.c b/engine/client/keys.c index deda2234..db8b6b94 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -1922,7 +1922,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) char *dc, *uc; char p[16]; int modifierstate; - int conkey = consolekeys[key] || (unicode && (key != '`' || key_linepos>1)); //if the input line is empty, allow ` to toggle the console, otherwise enter it as actual text. + int conkey = consolekeys[key] || ((unicode || key == '`') && (key != '`' || key_linepos>1)); //if the input line is empty, allow ` to toggle the console, otherwise enter it as actual text. // Con_Printf ("%i : %i : %i\n", key, unicode, down); //@@@ diff --git a/engine/client/m_options.c b/engine/client/m_options.c index a36af416..38a16384 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -88,6 +88,7 @@ void M_Menu_Options_f (void) MB_CONSOLECMD("Reset to defaults", "cvarreset *\nexec default.cfg\nplay misc/menu2.wav\n", "Reloads the default configuration."), MB_CONSOLECMD("Save all settings", "cfg_save\n", "Writes changed settings out to a config file."), MB_SPACING(4), + MB_SLIDER("Field of View", scr_fov, 80, 110, 5, NULL), MB_SLIDER("Mouse Speed", sensitivity, 1, 10, 0.2, NULL), MB_SLIDER("Crosshair", crosshair, 0, 22, 1, NULL), // move this to hud setup? MB_CHECKBOXFUNC("Always Run", M_Options_AlwaysRun, 0, "Set movement to run at fastest speed by default."), @@ -567,6 +568,8 @@ const char *presetexec[] = "cl_nolerp 1;" "r_lerpmuzzlehack 0;" "v_gunkick 0;" + "cl_rollangle 0;" + "cl_bob 0;" , // fast options "gl_texturemode ln;" @@ -600,6 +603,8 @@ const char *presetexec[] = "cl_nolerp 0;" "r_lerpmuzzlehack 1;" "v_gunkick 1;" + "cl_rollangle 2.0;" + "cl_bob 0.02;" , // nice options "r_stains 0.75;" diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 92c62aca..63a113b1 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -1940,9 +1940,10 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor info->ping = ping; info->players = 0; - info->maxplayers = atoi(Info_ValueForKey(msg, "maxclients")); - if (!info->maxplayers) - info->maxplayers = atoi(Info_ValueForKey(msg, "sv_maxclients")); + ping = atoi(Info_ValueForKey(msg, "maxclients")); + if (!ping) + ping = atoi(Info_ValueForKey(msg, "sv_maxclients")); + info->maxplayers = bound(0, ping, 255); info->tl = atoi(Info_ValueForKey(msg, "timelimit")); info->fl = atoi(Info_ValueForKey(msg, "fraglimit")); diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 2d99a303..604af5f5 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -142,7 +142,14 @@ typedef struct skytris_s { struct msurface_s *face; } skytris_t; -//these is the required render state for each particle +typedef struct skytriblock_s +{ + struct skytriblock_s *next; + int count; + skytris_t tris[1024]; +} skytriblock_t; + +//this is the required render state for each particle //dynamic per-particle stuff isn't important. only static state. typedef struct { enum {PT_NORMAL, PT_SPARK, PT_SPARKFAN, PT_TEXTUREDSPARK, PT_BEAM, PT_CDECAL, PT_UDECAL} type; @@ -153,6 +160,7 @@ typedef struct { float scalefactor; float invscalefactor; float stretch; + int premul; //0: direct rgba. 1: rgb*a,a (blend). 2: rgb*a,0 (add). } plooks_t; //these could be deltas or absolutes depending on ramping mode. @@ -239,8 +247,6 @@ typedef struct part_type_s { float spawnparam2; /* float spawnparam3; */ - float offsetup; // make this into a vec3_t later with dir, possibly for mdls - enum { SM_BOX, //box = even spread within the area SM_CIRCLE, //circle = around edge of a circle @@ -265,6 +271,7 @@ typedef struct part_type_s { vec4_t dl_decay; float dl_corona_intensity; float dl_corona_scale; + vec3_t dl_scales; //PT_NODLSHADOW int dl_cubemapnum; vec3_t stain_rgb; @@ -282,18 +289,18 @@ typedef struct part_type_s { struct part_type_s *nexttorun; unsigned int flags; -#define PT_VELOCITY 0x001 -#define PT_FRICTION 0x002 -#define PT_CHANGESCOLOUR 0x004 -#define PT_CITRACER 0x008 // Q1-style tracer behavior for colorindex -#define PT_INVFRAMETIME 0x010 // apply inverse frametime to count (causes emits to be per frame) -#define PT_AVERAGETRAIL 0x020 // average trail points from start to end, useful with t_lightning, etc -#define PT_NOSTATE 0x040 // don't use trailstate for this emitter (careful with assoc...) -#define PT_NOSPREADFIRST 0x080 // don't randomize org/vel for first generated particle -#define PT_NOSPREADLAST 0x100 // don't randomize org/vel for last generated particle -#define PT_TROVERWATER 0x200 // don't spawn if underwater -#define PT_TRUNDERWATER 0x400 // don't spawn if overwater -#define PT_NODLSHADOW 0x800 // dlights from this effect don't cast shadows. +#define PT_VELOCITY 0x0001 +#define PT_FRICTION 0x0002 +#define PT_CHANGESCOLOUR 0x0004 +#define PT_CITRACER 0x0008 // Q1-style tracer behavior for colorindex +#define PT_INVFRAMETIME 0x0010 // apply inverse frametime to count (causes emits to be per frame) +#define PT_AVERAGETRAIL 0x0020 // average trail points from start to end, useful with t_lightning, etc +#define PT_NOSTATE 0x0040 // don't use trailstate for this emitter (careful with assoc...) +#define PT_NOSPREADFIRST 0x0080 // don't randomize org/vel for first generated particle +#define PT_NOSPREADLAST 0x0100 // don't randomize org/vel for last generated particle +#define PT_TROVERWATER 0x0200 // don't spawn if underwater +#define PT_TRUNDERWATER 0x0400 // don't spawn if overwater +#define PT_NODLSHADOW 0x0800 // dlights from this effect don't cast shadows. unsigned int state; #define PS_INRUNLIST 0x1 // particle type is currently in execution list @@ -335,6 +342,8 @@ beamseg_t *free_beams; beamseg_t *beams; int r_numbeams; +skytriblock_t *skytrimem; + clippeddecal_t *free_decals; clippeddecal_t *decals; int r_numdecals; @@ -631,6 +640,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "{\n" "program defaultsprite\n" "nomipmaps\n" + "sort additive\n" "{\n" "map $diffuse\n" "blendfunc GL_SRC_ALPHA GL_ONE\n" @@ -647,6 +657,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "{\n" "program defaultsprite\n" "nomipmaps\n" + "sort additive\n" "{\n" "map $diffuse\n" "blendfunc GL_SRC_COLOR GL_ONE\n" @@ -657,12 +668,30 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "}\n" ; break; + case BM_PREMUL: + namepostfix = "_premul"; + defaultshader = + "{\n" + "program defaultsprite\n" + "nomipmaps\n" + "sort additive\n" + "{\n" + "map $diffuse\n" + "blendfunc GL_ONE GL_ONE_MINUS_SRC_ALPHA\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "}\n" + "polygonoffset\n" + "}\n" + ; + break; case BM_INVMODA: namepostfix = "_invmoda"; defaultshader = "{\n" "program defaultsprite\n" "nomipmaps\n" + "sort decal\n" "{\n" "map $diffuse\n" "blendfunc GL_ZERO GL_ONE_MINUS_SRC_ALPHA\n" @@ -679,6 +708,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "{\n" "program defaultsprite\n" "nomipmaps\n" + "sort decal\n" "{\n" "map $diffuse\n" "blendfunc GL_ZERO GL_ONE_MINUS_SRC_COLOR\n" @@ -708,7 +738,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) } memset(&tn, 0, sizeof(tn)); - tn.base = R_LoadHiResTexture(ptype->texname, "particles", 0); + tn.base = R_LoadHiResTexture(ptype->texname, "particles", IF_NOMIPMAP|(ptype->looks.premul?IF_PREMULTIPLYALPHA:0)); //mipmapping breaks particlefont stuff if (!TEXVALID(tn.base)) { /*okay, so the texture they specified wasn't valid either. use a fully default one*/ @@ -829,14 +859,17 @@ static void P_ResetToDefaults(part_type_t *ptype) ptype->spawnchance = 1; ptype->dl_time = 0; VectorSet(ptype->dl_rgb, 1, 1, 1); - ptype->dl_corona_intensity = 1; + ptype->dl_corona_intensity = 0.25; ptype->dl_corona_scale = 0.5; + VectorSet(ptype->dl_scales, 0, 1, 1); ptype->randsmax = 1; ptype->s2 = 1; ptype->t2 = 1; } +void Cmd_if_f(void); + //Uses FTE's multiline console stuff. //This is the function that loads the effect descriptions (via console). static void P_ParticleEffect_f(void) @@ -976,9 +1009,13 @@ static void P_ParticleEffect_f(void) var = Cmd_Argv(0); value = Cmd_Argv(1); - // TODO: switch this mess to some sort of binary tree to increase - // parse speed - if (!strcmp(var, "shader")) + // TODO: switch this mess to some sort of binary tree to increase parse speed + if (!strcmp(var, "if")) + { + //cheesy way to handle if statements inside particle configs. + Cmd_if_f(); + } + else if (!strcmp(var, "shader")) { Q_strncpyz(ptype->texname, ptype->name, sizeof(ptype->texname)); buf = Cbuf_GetNext(Cmd_ExecLevel, true); @@ -1078,7 +1115,8 @@ static void P_ParticleEffect_f(void) ptype->looks.scalefactor = atof(value); else if (!strcmp(var, "scaledelta")) ptype->scaledelta = atof(value); - + else if (!strcmp(var, "stretchfactor")) //affects sparks + ptype->looks.stretch = atof(value); else if (!strcmp(var, "step")) { @@ -1111,10 +1149,22 @@ static void P_ParticleEffect_f(void) { ptype->die = atof(value); if (Cmd_Argc()>2) - ptype->randdie = atof(Cmd_Argv(2)) - ptype->die; + { + float mn=ptype->die,mx=atof(Cmd_Argv(2)); + if (mn > mx) + { + mn = mx; + mx = ptype->die; + } + ptype->die = mx; + ptype->randdie = mx-mn; + } } else if (!strcmp(var, "diesubrand")) + { + Con_DPrintf("diesubrand is deprechiated, use die with two arguments\n"); ptype->randdie = atof(value); + } else if (!strcmp(var, "randomvel")) { @@ -1158,8 +1208,6 @@ static void P_ParticleEffect_f(void) } else if (!strcmp(var, "gravity")) ptype->gravity = atof(value); - else if (!strcmp(var, "clipbounce")) - ptype->clipbounce = atof(value); else if (!strcmp(var, "assoc")) { @@ -1367,7 +1415,7 @@ static void P_ParticleEffect_f(void) { if (!strcmp(value, "beam")) ptype->looks.type = PT_BEAM; - else if (!strcmp(value, "spark")) + else if (!strcmp(value, "spark") || !strcmp(value, "linespark")) ptype->looks.type = PT_SPARK; else if (!strcmp(value, "sparkfan") || !strcmp(value, "trianglefan")) ptype->looks.type = PT_SPARKFAN; @@ -1398,6 +1446,13 @@ static void P_ParticleEffect_f(void) } else if (!strcmp(var, "clipcount")) ptype->clipcount = atof(value); + else if (!strcmp(var, "clipbounce")) + ptype->clipbounce = atof(value); + else if (!strcmp(var, "bounce")) + { + ptype->cliptype = pnum; + ptype->clipbounce = atof(value); + } else if (!strcmp(var, "emit")) { @@ -1459,7 +1514,7 @@ static void P_ParticleEffect_f(void) ptype->spawnparam3 = atof(value); */ else if (!strcmp(var, "up")) - ptype->offsetup = atof(value); + ptype->orgbias[2] = atof(value); else if (!strcmp(var, "rampmode")) { if (!strcmp(value, "none")) @@ -1613,6 +1668,12 @@ static void P_ParticleEffect_f(void) ptype->flags = (ptype->flags & ~PT_NODLSHADOW) | (atof(value)?0:PT_NODLSHADOW); else if (!strcmp(var, "lightcubemap")) ptype->dl_cubemapnum = atoi(value); + else if (!strcmp(var, "lightscales")) + { //ambient diffuse specular + ptype->dl_scales[0] = atof(value); + ptype->dl_scales[1] = atof(Cmd_Argv(2)); + ptype->dl_scales[2] = atof(Cmd_Argv(3)); + } else if (!strcmp(var, "spawnstain")) { ptype->stain_radius = atof(value); @@ -1666,6 +1727,9 @@ static void P_ParticleEffect_f(void) if (!setalphadelta) ptype->alphachange = (-ptype->alphachange / ptype->die) * ptype->alpha; + if (!ptype->dl_time && ptype->dl_decay[3]) + ptype->dl_time = ptype->dl_radius / ptype->dl_decay[3]; + if (ptype->rampmode && !ptype->ramp) { ptype->rampmode = RAMP_NONE; @@ -1690,7 +1754,7 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) if (body == 0) { - Q_strncpyz(outstr, ptype->name, outstrlen); + Q_snprintfz(outstr, outstrlen, "%s.%s", ptype->config, ptype->name); return true; } @@ -1702,13 +1766,73 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) Q_strncatz(outstr, va("//this functionality is incomplete\n"), outstrlen); + switch (ptype->looks.type) + { + default: + case PT_NORMAL: + Q_strncatz(outstr, "type normal\n", outstrlen); + break; + case PT_SPARK: + Q_strncatz(outstr, "type linespark\n", outstrlen); + break; + case PT_SPARKFAN: + Q_strncatz(outstr, "type sparkfan\n", outstrlen); + break; + case PT_TEXTUREDSPARK: + Q_strncatz(outstr, "type texturedspark\n", outstrlen); + break; + case PT_BEAM: + Q_strncatz(outstr, "type beam\n", outstrlen); + break; + case PT_CDECAL: + Q_strncatz(outstr, "type cdecal\n", outstrlen); + break; + case PT_UDECAL: + Q_strncatz(outstr, "type udecal\n", outstrlen); + break; + } + switch (ptype->looks.blendmode) + { + case BM_BLEND: + Q_strncatz(outstr, "blend blendalpha\n", outstrlen); + break; + case BM_BLENDCOLOUR: + Q_strncatz(outstr, "blend blendcolour\n", outstrlen); + break; + case BM_ADDA: + Q_strncatz(outstr, "blend adda\n", outstrlen); + break; + case BM_ADDC: + Q_strncatz(outstr, "blend addc\n", outstrlen); + break; + case BM_SUBTRACT: + Q_strncatz(outstr, "blend subtract\n", outstrlen); + break; + case BM_INVMODA: + Q_strncatz(outstr, "blend invmoda\n", outstrlen); + break; + case BM_INVMODC: + if (ptype->looks.premul) + Q_strncatz(outstr, "blend premul_subtract\n", outstrlen); + else + Q_strncatz(outstr, "blend invmodc\n", outstrlen); + break; + case BM_PREMUL: + if (ptype->looks.premul == 2) + Q_strncatz(outstr, "blend premul_add\n", outstrlen); + else + Q_strncatz(outstr, "blend premul_blend\n", outstrlen); + break; + } + for (i = 0; i < ptype->nummodels; i++) { Q_strncatz(outstr, va("model \"%s\" %g %g %g %g \"%s\"\n", ptype->models[i].name, ptype->models[i].framestart, ptype->models[i].frameend, ptype->models[i].framerate, ptype->models[i].alpha, ptype->assoc==P_INVALID?"":part_type[ptype->assoc].name), outstrlen); } if (*ptype->texname) - { + { //note: particles don't really know if the shader was embedded or not. the shader system handles all that. + //this means that you'll really need to use external shaders for this to work. Q_strncatz(outstr, va("texture \"%s\"\n", ptype->texname), 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); } @@ -1717,17 +1841,17 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) Q_strncatz(outstr, va("count %g\n", ptype->count), outstrlen); if (ptype->rgb[0] || ptype->rgb[1] || ptype->rgb[2]) - Q_strncatz(outstr, va("rgb %g %g %g\n", ptype->rgb[0]*255, ptype->rgb[1]*255, ptype->rgb[2]*255), outstrlen); + Q_strncatz(outstr, va("rgbf %g %g %g\n", ptype->rgb[0], ptype->rgb[1], ptype->rgb[2]), outstrlen); if (ptype->rgbrand[0] || ptype->rgbrand[1] || ptype->rgbrand[2]) - Q_strncatz(outstr, va("rgbrand %g %g %g\n", ptype->rgbrand[0]*255, ptype->rgbrand[1]*255, ptype->rgbrand[2]*255), outstrlen); + Q_strncatz(outstr, va("rgbrandf %g %g %g\n", ptype->rgbrand[0], ptype->rgbrand[1], ptype->rgbrand[2]), outstrlen); if (ptype->rgbrandsync[0] || ptype->rgbrandsync[1] || ptype->rgbrandsync[2]) Q_strncatz(outstr, va("rgbrandsync %g %g %g\n", ptype->rgbrandsync[0], ptype->rgbrandsync[1], ptype->rgbrandsync[2]), outstrlen); if (ptype->rgbchange[0] || ptype->rgbchange[1] || ptype->rgbchange[2]) - Q_strncatz(outstr, va("rgbchange %g %g %g\n", ptype->rgbchange[0]*255, ptype->rgbchange[1]*255, ptype->rgbchange[2]*255), outstrlen); + Q_strncatz(outstr, va("rgbdeltaf %g %g %g\n", ptype->rgbchange[0], ptype->rgbchange[1], ptype->rgbchange[2]), outstrlen); if (ptype->rgbchangetime) Q_strncatz(outstr, va("rgbchangetime %g\n", ptype->rgbchangetime), outstrlen); - if (ptype->colorindex) + if (ptype->colorindex != -1) Q_strncatz(outstr, va("colorindex %i\n", ptype->colorindex), outstrlen); if (ptype->colorrand) Q_strncatz(outstr, va("colorrand %i\n", ptype->colorrand), outstrlen); @@ -1741,24 +1865,57 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) if (ptype->scale || ptype->scalerand) Q_strncatz(outstr, va("scale %g %g\n", ptype->scale, ptype->scale+ptype->scalerand), outstrlen); -// if (ptype->looks.scalefactor) +// if (ptype->looks.scalefactor) //always write scalefactor, to avoid issues with defaults. Q_strncatz(outstr, va("scalefactor %g\n", ptype->looks.scalefactor), outstrlen); if (ptype->scaledelta) Q_strncatz(outstr, va("scaledelta %g\n", ptype->scaledelta), outstrlen); + if (ptype->looks.stretch) + Q_strncatz(outstr, va("stretchfactor %g\n", ptype->looks.stretch), outstrlen); if (ptype->die || ptype->randdie) Q_strncatz(outstr, va("die %g %g\n", ptype->die, ptype->die+ptype->randdie), outstrlen); - if (ptype->randomvel || ptype->randomvelvert || ptype->randomvelvertbias) - Q_strncatz(outstr, va("randomvel %g %g %g\n", ptype->randomvel, ptype->randomvelvertbias - ptype->randomvelvert, ptype->randomvelvertbias + ptype->randomvelvert), outstrlen); + switch(ptype->spawnmode) + { + case SM_CIRCLE: + Q_strncatz(outstr, va("spawnmode circle %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + case SM_BALL: + Q_strncatz(outstr, va("spawnmode ball %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + case SM_SPIRAL: + Q_strncatz(outstr, va("spawnmode spiral %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + case SM_TRACER: + Q_strncatz(outstr, va("spawnmode tracer %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + case SM_TELEBOX: + Q_strncatz(outstr, va("spawnmode telebox %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + case SM_LAVASPLASH: + Q_strncatz(outstr, va("spawnmode lavasplash %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + case SM_UNICIRCLE: + Q_strncatz(outstr, va("spawnmode uniformcircle %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + case SM_FIELD: + Q_strncatz(outstr, va("spawnmode syncfield %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + case SM_DISTBALL: + Q_strncatz(outstr, va("spawnmode distball %g %g\n", ptype->spawnparam1, ptype->spawnparam2), outstrlen); + break; + } + if (ptype->spawnvel || ptype->spawnvelvert) + Q_strncatz(outstr, va("spawnvel %g %g\n", ptype->spawnvel, ptype->spawnvelvert), outstrlen); + if (ptype->areaspread || ptype->areaspreadvert) + Q_strncatz(outstr, va("spawnorg %g %g\n", ptype->areaspread, ptype->areaspreadvert), outstrlen); if (ptype->veladd) Q_strncatz(outstr, va("veladd %g\n", ptype->veladd), outstrlen); if (ptype->orgadd) Q_strncatz(outstr, va("orgadd %g\n", ptype->orgadd), outstrlen); - - if (ptype->spawnvel || ptype->spawnvelvert) - Q_strncatz(outstr, va("spawnvel %g %g\n", ptype->spawnvel, ptype->spawnvelvert), outstrlen); + if (ptype->randomvel || ptype->randomvelvert || ptype->randomvelvertbias) + Q_strncatz(outstr, va("randomvel %g %g %g\n", ptype->randomvel, ptype->randomvelvertbias - ptype->randomvelvert, ptype->randomvelvertbias + ptype->randomvelvert), outstrlen); if (ptype->assoc != P_INVALID) Q_strncatz(outstr, va("assoc \"%s\"\n", part_type[ptype->assoc].name), outstrlen); @@ -1779,13 +1936,13 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) Q_strncatz(outstr, va("lightshadows %g\n", (ptype->flags & PT_NODLSHADOW)?0.0f:1.0f), outstrlen); Q_strncatz(outstr, va("lightcubemap %i\n", ptype->dl_cubemapnum), outstrlen); Q_strncatz(outstr, va("lightcorona %g %g\n", ptype->dl_corona_intensity, ptype->dl_corona_scale), outstrlen); + Q_strncatz(outstr, va("lightscales %g %g %g\n", ptype->dl_scales[0], ptype->dl_scales[1], ptype->dl_scales[2]), outstrlen); } if (ptype->stain_radius) Q_strncatz(outstr, va("spawnstain %g %g %g %g\n", ptype->stain_radius, ptype->stain_rgb[0], ptype->stain_rgb[1], ptype->stain_rgb[2]), outstrlen); if (ptype->stainonimpact) Q_strncatz(outstr, va("stains %g\n", ptype->stainonimpact), outstrlen); - return true; #if 0 @@ -1815,8 +1972,6 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) float spawnparam2; /* float spawnparam3; */ - float offsetup; // make this into a vec3_t later with dir, possibly for mdls - enum { SM_BOX, //box = even spread within the area SM_CIRCLE, //circle = around edge of a circle @@ -1865,7 +2020,7 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) static void P_ExportAllEffects_f(void) { char effect[8192]; - int i; + int i, assoc, n; vfsfile_t *outf; char fname[64] = "particles/export.cfg"; FS_CreatePath("particles/", FS_GAMEONLY); @@ -1879,12 +2034,24 @@ static void P_ExportAllEffects_f(void) for (i = 0; i < numparticletypes; i++) { PScript_Query(i, 0, effect, sizeof(effect)); - VFS_PUTS(outf, "r_part "); - VFS_PUTS(outf, effect); - VFS_PUTS(outf, "\n{\n"); - PScript_Query(i, 1, effect, sizeof(effect)); - VFS_PUTS(outf, effect); - VFS_PUTS(outf, "}\n"); + if (strchr(effect, '+')) + continue; + assoc = i; + while(assoc != P_INVALID) + { + n = part_type[assoc].assoc; + part_type[assoc].assoc = P_INVALID; + VFS_PUTS(outf, "r_part "); + VFS_PUTS(outf, effect); + VFS_PUTS(outf, "\n{\n"); + PScript_Query(assoc, 1, effect, sizeof(effect)); + VFS_PUTS(outf, effect); + VFS_PUTS(outf, "}\n"); + part_type[assoc].assoc = n; + assoc = n; + + Q_snprintfz(effect, sizeof(effect), "%s.+%s", part_type[i].config, part_type[i].name); + } } VFS_CLOSE(outf); @@ -1932,6 +2099,7 @@ static void P_PartInfo_f (void) { particle_t *p; part_type_t *ptype; + int t = 0, r = 0, e = 0; int i, j; @@ -1942,6 +2110,7 @@ static void P_PartInfo_f (void) Con_Printf("%i free particles\n", i); + Con_Printf("Full list of effects:\n"); for (i = 0; i < numparticletypes; i++) { j = 0; @@ -1954,6 +2123,7 @@ static void P_PartInfo_f (void) if (!(part_type[i].state & PS_INRUNLIST)) Con_Printf(" NOT RUNNING\n"); } + t += j; } Con_Printf("Running effects:\n"); @@ -1966,8 +2136,11 @@ static void P_PartInfo_f (void) Con_Printf("Type %s = %i total\n", ptype->name, j); + r += j; + e++; } Con_Printf("End of list\n"); + Con_Printf("%i total, %i running, %i effects.\n", t, r, e); } #endif @@ -1988,6 +2161,8 @@ void FinishParticleType(part_type_t *ptype) else ptype->die = 15; } + if (ptype->dl_decay[3] && !ptype->dl_time) + ptype->dl_time = ptype->dl_radius / ptype->dl_decay[3]; if (ptype->looks.scalefactor > 1 && !ptype->looks.invscalefactor) { ptype->scale *= ptype->looks.scalefactor; @@ -1999,22 +2174,13 @@ void FinishParticleType(part_type_t *ptype) ptype->looks.stretch *= 0.04; } -static void P_ImportEffectInfo_f(void) +static void P_ImportEffectInfo(char *config, char *line) { part_type_t *ptype = NULL; int parenttype; - char *file, *line; char arg[8][1024]; int args = 0; - char *config = "effectinfo"; - FS_LoadFile("effectinfo.txt", (void**)&file); - if (!file) - { - Con_Printf("effectinfo.txt not found\n"); - return; - } - line = file; for (;;) { if (!*line) @@ -2045,7 +2211,20 @@ static void P_ImportEffectInfo_f(void) if (ptype) { if (ptype->looks.type == PT_CDECAL) - ptype->scale *= 0.25; + { + if (ptype->die == 9999) + ptype->die = 20; + ptype->alphachange = -(ptype->alpha / ptype->die); + } + else if (ptype->looks.type == PT_NORMAL) + { + //fte's textured particles are *0.25 for some reason. + ptype->scale *= 4; + ptype->scalerand *= 4; + ptype->scaledelta *= 4; + } + if (!ptype->areaspreadvert) + ptype->areaspreadvert = 0.001; FinishParticleType(ptype); } @@ -2069,7 +2248,7 @@ static void P_ImportEffectInfo_f(void) break; } } - // P_ResetToDefaults(ptype); + P_ResetToDefaults(ptype); ptype->loaded = part_parseweak?1:2; ptype->scale = 1; ptype->alpha = 0; @@ -2081,7 +2260,7 @@ static void P_ImportEffectInfo_f(void) ptype->rgb[1] = 1; ptype->rgb[2] = 1; - ptype->spawnmode = SM_BOX; + ptype->spawnmode = SM_BALL; ptype->colorindex = -1; ptype->spawnchance = 1; @@ -2089,10 +2268,11 @@ static void P_ImportEffectInfo_f(void) ptype->looks.scalefactor = 2; ptype->looks.invscalefactor = 0; ptype->looks.type = PT_NORMAL; - ptype->looks.blendmode = BM_BLEND; + ptype->looks.blendmode = BM_PREMUL; + ptype->looks.premul = 1; ptype->looks.stretch = 1; - ptype->dl_time = 100; + ptype->dl_time = 0; } else if (!ptype) { @@ -2109,52 +2289,62 @@ static void P_ImportEffectInfo_f(void) { ptype->looks.type = PT_CDECAL; ptype->looks.blendmode = BM_INVMODC; + ptype->looks.premul = 2; } else if (!strcmp(arg[1], "udecal")) { ptype->looks.type = PT_UDECAL; ptype->looks.blendmode = BM_INVMODC; + ptype->looks.premul = 2; } else if (!strcmp(arg[1], "alphastatic")) { ptype->looks.type = PT_NORMAL; - ptype->looks.blendmode = BM_BLEND; + ptype->looks.blendmode = BM_PREMUL;//BM_BLEND; + ptype->looks.premul = 1; } else if (!strcmp(arg[1], "static")) { ptype->looks.type = PT_NORMAL; - ptype->looks.blendmode = BM_ADDA; + ptype->looks.blendmode = BM_PREMUL;//BM_ADDA; + ptype->looks.premul = 2; } else if (!strcmp(arg[1], "smoke")) { ptype->looks.type = PT_NORMAL; - ptype->looks.blendmode = BM_ADDA; + ptype->looks.blendmode = BM_PREMUL;//BM_ADDA; + ptype->looks.premul = 2; } else if (!strcmp(arg[1], "spark")) { ptype->looks.type = PT_TEXTUREDSPARK; - ptype->looks.blendmode = BM_ADDA; + ptype->looks.blendmode = BM_PREMUL;//BM_ADDA; + ptype->looks.premul = 2; } else if (!strcmp(arg[1], "bubble")) { ptype->looks.type = PT_NORMAL; - ptype->looks.blendmode = BM_ADDA; + ptype->looks.blendmode = BM_PREMUL;//BM_ADDA; + ptype->looks.premul = 2; } else if (!strcmp(arg[1], "blood")) { ptype->looks.type = PT_NORMAL; ptype->looks.blendmode = BM_INVMODC; + ptype->looks.premul = 2; ptype->gravity = 800*1; } else if (!strcmp(arg[1], "beam")) { ptype->looks.type = PT_BEAM; - ptype->looks.blendmode = BM_ADDA; + ptype->looks.blendmode = BM_PREMUL;//BM_ADDA; + ptype->looks.premul = 2; } else if (!strcmp(arg[1], "snow")) { ptype->looks.type = PT_NORMAL; - ptype->looks.blendmode = BM_ADDA; + ptype->looks.blendmode = BM_PREMUL;//BM_ADDA; + ptype->looks.premul = 2; //should have some sort of wind/flutter with it } else @@ -2179,11 +2369,11 @@ static void P_ImportEffectInfo_f(void) else if (!strcmp(arg[0], "size") && args == 3) { float s1 = atof(arg[1]), s2 = atof(arg[2]); - ptype->scale = s1 * 4; - ptype->scalerand = (s2-s1) * 4; + ptype->scale = s1; + ptype->scalerand = (s2-s1); } else if (!strcmp(arg[0], "sizeincrease") && args == 2) - ptype->scaledelta = atof(arg[1]) * 4; + ptype->scaledelta = atof(arg[1]); else if (!strcmp(arg[0], "color") && args == 3) { unsigned int rgb1 = strtoul(arg[1], NULL, 0), rgb2 = strtoul(arg[2], NULL, 0); @@ -2198,9 +2388,9 @@ static void P_ImportEffectInfo_f(void) else if (!strcmp(arg[0], "alpha") && args == 4) { float a1 = atof(arg[1]), a2 = atof(arg[2]), f = atof(arg[3]); - ptype->alpha = a1/255; - ptype->alpharand = (a2-a1)/255; - ptype->alphachange = -f/255; + ptype->alpha = a1/256; + ptype->alpharand = (a2-a1)/256; + ptype->alphachange = -f/256; } else if (!strcmp(arg[0], "velocityoffset") && args == 4) ; /*a 3d world-coord addition*/ @@ -2256,11 +2446,20 @@ static void P_ImportEffectInfo_f(void) else if (!strcmp(arg[0], "blend") && args == 2) { if (!strcmp(arg[1], "invmod")) + { ptype->looks.blendmode = BM_INVMODC; + ptype->looks.premul = 2; + } else if (!strcmp(arg[1], "alpha")) - ptype->looks.blendmode = BM_BLEND; + { + ptype->looks.blendmode = BM_PREMUL; + ptype->looks.premul = 1; + } else if (!strcmp(arg[1], "add")) - ptype->looks.blendmode = BM_ADDA; + { + ptype->looks.blendmode = BM_PREMUL; + ptype->looks.premul = 2; + } else Con_Printf("effectinfo 'blend %s' not supported\n", arg[1]); } @@ -2271,7 +2470,10 @@ static void P_ImportEffectInfo_f(void) else if (!strcmp(arg[1], "spark")) ptype->looks.type = PT_TEXTUREDSPARK; else if (!strcmp(arg[1], "oriented")) //FIXME: not sure this points the right way. also, its double-sided in dp. - ptype->looks.type = PT_UDECAL; + { + if (ptype->looks.type != PT_CDECAL) + ptype->looks.type = PT_UDECAL; + } else if (!strcmp(arg[1], "beam")) ptype->looks.type = PT_BEAM; else @@ -2295,7 +2497,7 @@ static void P_ImportEffectInfo_f(void) ptype->dl_cubemapnum = atoi(arg[1]); else if (!strcmp(arg[0], "lightcorona") && args == 3) { - ptype->dl_corona_intensity = atof(arg[1]); + ptype->dl_corona_intensity = atof(arg[1])*0.25; //dp scales them by 0.25 ptype->dl_corona_scale = atof(arg[2]); } #if 1 @@ -2322,14 +2524,44 @@ static void P_ImportEffectInfo_f(void) if (ptype) { if (ptype->looks.type == PT_CDECAL) - ptype->scale *= 0.25; + { + if (ptype->die == 9999) + ptype->die = 20; + ptype->alphachange = -(ptype->alpha / ptype->die); + } + else if (ptype->looks.type == PT_NORMAL) + { + //fte's textured particles are *0.25 for some reason. + ptype->scale *= 4; + ptype->scalerand *= 4; + ptype->scaledelta *= 4; + } + if (!ptype->areaspreadvert) + ptype->areaspreadvert = 0.001; FinishParticleType(ptype); } - FS_FreeFile(file); r_plooksdirty = true; } +static void P_ImportEffectInfo_f(void) +{ + char *file, *line; + int args = 0; + char *config = "effectinfo"; + + FS_LoadFile(va("%s.txt", config), (void**)&file); + + if (!file) + { + Con_Printf("effectinfo.txt not found\n"); + return; + } + line = file; + P_ImportEffectInfo(config, file); + FS_FreeFile(file); +} + /* =============== R_InitParticles @@ -2469,6 +2701,13 @@ static void PScript_Shutdown (void) BZ_Free (decals); BZ_Free (trailstates); + while(skytrimem) + { + void *f = skytrimem; + skytrimem = skytrimem->next; + BZ_Free(f); + } + r_numparticles = 0; } @@ -2850,9 +3089,16 @@ static void R_Part_SkyTri(float *v1, float *v2, float *v3, msurface_t *surf, int skytris_t *st; - st = NULL;//Hunk_Alloc(sizeof(skytris_t)); - if (!st) - return; + skytriblock_t *mem = skytrimem; + if (!mem || mem->count >= sizeof(mem->tris)/sizeof(mem->tris[0])) + { + skytrimem = BZ_Malloc(sizeof(*skytrimem)); + skytrimem->next = mem; + skytrimem->count = 0; + mem = skytrimem; + } + + st = &mem->tris[mem->count++]; st->next = part_type[ptype].skytris; VectorCopy(v1, st->org); VectorSubtract(v2, st->org, st->x); @@ -3199,7 +3445,7 @@ static void PScript_ApplyOrgVel(vec3_t oorg, vec3_t ovel, vec3_t eforg, vec3_t e oorg[0] = eforg[0] + arsvec[0]; oorg[1] = eforg[1] + arsvec[1]; - oorg[2] = eforg[2] + arsvec[2] + ptype->offsetup; + oorg[2] = eforg[2] + arsvec[2]; // apply arsvec+ofsvec if (efdir) @@ -3213,13 +3459,14 @@ static void PScript_ApplyOrgVel(vec3_t oorg, vec3_t ovel, vec3_t eforg, vec3_t e oorg[2] += efdir[2]*ptype->orgadd; } else - { + {//efdir is effectively up - '0 0 -1' ovel[0] += ofsvec[0]*ptype->spawnvel; ovel[1] += ofsvec[1]*ptype->spawnvel; ovel[2] += ofsvec[2]*ptype->spawnvelvert - ptype->veladd; oorg[2] -= ptype->orgadd; } + VectorAdd(oorg, ptype->orgbias, oorg); } static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, int dlkey, float countscale) @@ -3253,6 +3500,11 @@ static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, in dl->decay = ptype->dl_decay[3]; dl->corona = ptype->dl_corona_intensity; dl->coronascale = ptype->dl_corona_scale; +#ifdef RTLIGHTS + dl->lightcolourscales[0] = ptype->dl_scales[0]; + dl->lightcolourscales[1] = ptype->dl_scales[1]; + dl->lightcolourscales[2] = ptype->dl_scales[2]; +#endif if (ptype->flags & PT_NODLSHADOW) dl->flags |= LFLAG_NOSHADOWS; if (ptype->dl_cubemapnum) @@ -3329,6 +3581,18 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, while(ptype) { + if (r_part_contentswitch.ival && (ptype->flags & (PT_TRUNDERWATER | PT_TROVERWATER)) && cl.worldmodel) + { + int cont; + cont = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, org); + + if ((ptype->flags & PT_TROVERWATER) && (cont & FTECONTENTS_FLUID)) + goto skip; + if ((ptype->flags & PT_TRUNDERWATER) && !(cont & FTECONTENTS_FLUID)) + goto skip; + } + + PScript_EffectSpawned(ptype, org, dir, 0, count); if (ptype->looks.type == PT_CDECAL) @@ -3348,13 +3612,13 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, if (!free_decals) return 0; + VectorCopy(org, bestorg); if (!dir || (dir[0] == 0 && dir[1] == 0 && dir[2] == 0)) { bestdir[0] = 0; bestdir[1] = 0.73; bestdir[2] = 0.73; dist = 1; - VectorCopy(org, bestorg); for (i = 0; i < 6; i++) { if (i >= 3) @@ -3372,7 +3636,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, VectorSubtract(org, t2, tangent); VectorAdd(org, t2, t2); - if (cl.worldmodel->funcs.NativeTrace (cl.worldmodel, 0, 0, NULL, tangent, t2, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr)) + if (cl.worldmodel && cl.worldmodel->funcs.NativeTrace (cl.worldmodel, 0, 0, NULL, tangent, t2, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr)) { if (tr.fraction < dist) { @@ -3383,7 +3647,6 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, } } dir = bestdir; - org = bestorg; } VectorInverse(dir); VectorNormalize(dir); @@ -3401,7 +3664,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, sw /= m; tw /= m; - decalcount = Q1BSP_ClipDecal(org, dir, tangent, t2, m, &decverts); + decalcount = Q1BSP_ClipDecal(bestorg, dir, tangent, t2, m, &decverts); while(decalcount) { if (!free_decals) @@ -3418,7 +3681,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, for (i = 0; i < 3; i++) { - VectorSubtract(d->vertex[i], org, vec); + VectorSubtract(d->vertex[i], bestorg, vec); d->texcoords[i][0] = (DotProduct(vec, t2)*sw)+sb; d->texcoords[i][1] = (DotProduct(vec, tangent)*tw)+tb; } @@ -3770,7 +4033,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, p->org[0] = org[0] + arsvec[0]; p->org[1] = org[1] + arsvec[1]; - p->org[2] = org[2] + arsvec[2] + ptype->offsetup; + p->org[2] = org[2] + arsvec[2]; // apply arsvec+ofsvec if (dir) @@ -3835,6 +4098,8 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, ptype->state |= PS_INRUNLIST; } +skip: + // go to next associated effect if (ptype->assoc < 0) break; @@ -4209,7 +4474,7 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype VectorScale(vec, step, vstep); // add offset - start[2] += ptype->offsetup; + VectorAdd(start, ptype->orgbias, start); // spawn mode precalculations if (ptype->spawnmode == SM_SPIRAL) @@ -4515,7 +4780,7 @@ static void P_ParticleTrailDraw (vec3_t startpos, vec3_t end, part_type_t *ptype p->org[1] += vec[1]*ptype->orgadd; p->org[2] += vec[2]*ptype->orgadd; } - VectorAdd(p->org, ptype->orgbias, p->org); +// VectorAdd(p->org, ptype->orgbias, p->org); } VectorAdd (start, vstep, start); @@ -4828,10 +5093,27 @@ static void R_AddTSparkParticle(scenetris_t *t, particle_t *p, plooks_t *type) scale = 0.25 + scale * 0.001; } - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+1]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+2]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+3]); + if (type->premul) + { + vec4_t rgba; + float a = p->rgba[3]; + if (a > 1) + a = 1; + rgba[0] = p->rgba[0] * a; + rgba[1] = p->rgba[1] * a; + rgba[2] = p->rgba[2] * a; + rgba[3] = (type->premul==2)?0:a; + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+2]); + } + else + { + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+2]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+3]); + } Vector2Set(cl_strisvertt[cl_numstrisvert+0], p->s1, p->t1); Vector2Set(cl_strisvertt[cl_numstrisvert+1], p->s1, p->t2); @@ -4842,22 +5124,29 @@ static void R_AddTSparkParticle(scenetris_t *t, particle_t *p, plooks_t *type) if (type->stretch) { + VectorMA(p->org, -type->stretch, p->vel, o2); + VectorSubtract(r_refdef.vieworg, o2, v); + + CrossProduct(v, p->vel, cr); + VectorNormalize(cr); + + VectorMA(o2, -p->scale/2, cr, cl_strisvertv[cl_numstrisvert+0]); + VectorMA(o2, p->scale/2, cr, cl_strisvertv[cl_numstrisvert+1]); + VectorMA(p->org, type->stretch, p->vel, o2); - VectorMA(p->org, -type->stretch, p->vel, v); - VectorSubtract(r_refdef.vieworg, v, v); } else { VectorMA(p->org, 0.1, p->vel, o2); VectorSubtract(r_refdef.vieworg, p->org, v); + + + CrossProduct(v, p->vel, cr); + VectorNormalize(cr); + + VectorMA(p->org, -p->scale/2, cr, cl_strisvertv[cl_numstrisvert+0]); + VectorMA(p->org, p->scale/2, cr, cl_strisvertv[cl_numstrisvert+1]); } - - CrossProduct(v, p->vel, cr); - VectorNormalize(cr); - - VectorMA(p->org, -p->scale/2, cr, cl_strisvertv[cl_numstrisvert+0]); - VectorMA(p->org, p->scale/2, cr, cl_strisvertv[cl_numstrisvert+1]); - VectorSubtract(r_refdef.vieworg, o2, v); CrossProduct(v, p->vel, cr); VectorNormalize(cr); @@ -5024,9 +5313,26 @@ static void R_AddClippedDecal(scenetris_t *t, clippeddecal_t *d, plooks_t *type) cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert); } - Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+0]); - Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+1]); - Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+2]); + if (type->premul) + { + vec4_t rgba; + float a = d->rgba[3]; + if (a > 1) + a = 1; + rgba[0] = d->rgba[0] * a; + rgba[1] = d->rgba[1] * a; + rgba[2] = d->rgba[2] * a; + rgba[3] = (type->premul==2)?0:a; + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+2]); + } + else + { + Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(d->rgba, cl_strisvertc[cl_numstrisvert+2]); + } Vector2Copy(d->texcoords[0], cl_strisvertt[cl_numstrisvert+0]); Vector2Copy(d->texcoords[1], cl_strisvertt[cl_numstrisvert+1]); @@ -5064,10 +5370,28 @@ static void R_AddUnclippedDecal(scenetris_t *t, particle_t *p, plooks_t *type) cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert); } - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+1]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+2]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+3]); + if (type->premul) + { + vec4_t rgba; + float a = p->rgba[3]; + if (a > 1) + a = 1; + rgba[0] = p->rgba[0] * a; + rgba[1] = p->rgba[1] * a; + rgba[2] = p->rgba[2] * a; + rgba[3] = (type->premul==2)?0:a; + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+2]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+3]); + } + else + { + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+2]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+3]); + } Vector2Set(cl_strisvertt[cl_numstrisvert+0], p->s1, p->t1); Vector2Set(cl_strisvertt[cl_numstrisvert+1], p->s1, p->t2); @@ -5149,10 +5473,28 @@ static void R_AddTexturedParticle(scenetris_t *t, particle_t *p, plooks_t *type) scale = 0.25 + scale * 0.001; } - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+1]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+2]); - Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+3]); + if (type->premul) + { + vec4_t rgba; + float a = p->rgba[3]; + if (a > 1) + a = 1; + rgba[0] = p->rgba[0] * a; + rgba[1] = p->rgba[1] * a; + rgba[2] = p->rgba[2] * a; + rgba[3] = (type->premul==2)?0:a; + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+2]); + Vector4Copy(rgba, cl_strisvertc[cl_numstrisvert+3]); + } + else + { + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+1]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+2]); + Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+3]); + } Vector2Set(cl_strisvertt[cl_numstrisvert+0], p->s1, p->t1); Vector2Set(cl_strisvertt[cl_numstrisvert+1], p->s1, p->t2); @@ -5690,13 +6032,10 @@ static void PScript_DrawParticleTypes (void) if (part_type + type->cliptype == type) { //bounce - dist = DotProduct(p->vel, normal) * (-1-(rand()/(float)0x7fff)/2); - + dist = DotProduct(p->vel, normal);// * (-1-(rand()/(float)0x7fff)/2); + dist *= -type->clipbounce; VectorMA(p->vel, dist, normal, p->vel); VectorCopy(stop, p->org); - p->vel[0] *= type->clipbounce; - p->vel[1] *= type->clipbounce; - p->vel[2] *= type->clipbounce; if (!*type->texname && Length(p->vel)<1000*pframetime && type->looks.type == PT_NORMAL) { @@ -5740,6 +6079,22 @@ static void PScript_DrawParticleTypes (void) if (scenetri) { + if (cl_numstrisvert - scenetri->firstvert >= MAX_INDICIES-6) + { + //generate a new mesh if the old one overflowed. yay smc... + if (cl_numstris == cl_maxstris) + { + cl_maxstris+=8; + cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); + } + scenetri = &cl_stris[cl_numstris++]; + scenetri->shader = scenetri[-1].shader; + scenetri->firstidx = cl_numstrisidx; + scenetri->firstvert = cl_numstrisvert; + scenetri->flags = scenetri[-1].flags; + scenetri->numvert = 0; + scenetri->numidx = 0; + } tdraw(scenetri, p, type->slooks); } else if (pdraw) diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index afe618a7..9fcbd042 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2215,7 +2215,7 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa float *start = G_VECTOR(OFS_PARM2); float *end = G_VECTOR(OFS_PARM3); - if (csqc_isdarkplaces) + if (G_INT(OFS_PARM1) >= MAX_EDICTS) { efnum = G_FLOAT(OFS_PARM1); ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); @@ -5342,7 +5342,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks csqcprogs = InitProgs(&csqcprogparms); csqc_world.progs = csqcprogs; csqc_world.usesolidcorpse = true; - PR_Configure(csqcprogs, pr_csqc_memsize.ival, 16); + PR_Configure(csqcprogs, pr_csqc_memsize.ival, 16, pr_enable_profiling.ival); csqc_world.worldmodel = cl.worldmodel; csqc_world.Event_Touch = CSQC_Event_Touch; csqc_world.Event_Think = CSQC_Event_Think; @@ -5688,6 +5688,12 @@ void CSQC_WatchPoint_f(void) else Con_Printf("Watchpoint cleared\n"); } +void PR_CSProfile_f(void) +{ + if (csqcprogs && csqcprogs->DumpProfile) + if (!csqcprogs->DumpProfile(csqcprogs)) + Con_Printf("Please set pr_enable_profiling and restart the map first\n"); +} static void CSQC_GameCommand_f(void); void CSQC_RegisterCvarsAndThings(void) @@ -5698,6 +5704,7 @@ void CSQC_RegisterCvarsAndThings(void) Cmd_AddCommand("breakpoint_csqc", CSQC_Breakpoint_f); Cmd_AddCommand ("watchpoint_csqc", CSQC_WatchPoint_f); Cmd_AddCommandD("poke_csqc", CSQC_Poke_f, "Allows you to inspect/debug "); + Cmd_AddCommand ("profile_csqc", PR_CSProfile_f); Cvar_Register(&pr_csqc_formenus, CSQCPROGSGROUP); Cvar_Register(&pr_csqc_memsize, CSQCPROGSGROUP); diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index d814fa0e..dab774d4 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -779,6 +779,18 @@ void QCBUILTIN PF_SubConGetSet (pubprogfuncs_t *prinst, struct globalvars_s *pr_ con->parseflags |= PFS_FORCEUTF8; } } + else if (!strcmp(field, "close")) + { + RETURN_TSTRING("0"); //meant to return the old state... + if (value && atoi(value)) + Con_Destroy(con); + } + else if (!strcmp(field, "clear")) + { + RETURN_TSTRING(con->linecount?"0":"1"); + if (value && atoi(value)) + Con_ClearCon(con); + } else if (!strcmp(field, "hidden")) { RETURN_TSTRING((con->flags & CON_HIDDEN)?"1":"0"); @@ -985,7 +997,12 @@ static void QCBUILTIN PF_menu_cvar_string (pubprogfuncs_t *prinst, struct global { const char *str = PR_GetStringOfs(prinst, OFS_PARM0); cvar_t *cv = Cvar_Get(RemapCvarNameFromDPToFTE(str), "", 0, "QC variables"); - G_INT( OFS_RETURN ) = (int)PR_SetString( prinst, cv->string ); + if (!cv) + G_INT(OFS_RETURN) = 0; + else if (cv->latched_string) + G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cv->latched_string); + else + G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cv->string); } qboolean M_Vid_GetMode(int num, int *w, int *h); @@ -1093,10 +1110,13 @@ void QCBUILTIN PF_cl_setkeydest (pubprogfuncs_t *prinst, struct globalvars_s *pr { case 0: // key_game - if (!(cls.state == ca_active)) + if (cls.state == ca_disconnected) Key_Dest_Add(kdm_console); - Key_Dest_Remove(kdm_menu); - Key_Dest_Remove(kdm_message); + if (Key_Dest_Has(kdm_menu)) + { + Key_Dest_Remove(kdm_menu); + Key_Dest_Remove(kdm_message); + } break; case 2: // key_menu @@ -1959,7 +1979,7 @@ qboolean MP_Init (void) int mprogs; Con_DPrintf("Initializing menu.dat\n"); menu_world.progs = InitProgs(&menuprogparms); - PR_Configure(menu_world.progs, 64*1024*1024, 1); + PR_Configure(menu_world.progs, 64*1024*1024, 1, pr_enable_profiling.ival); mprogs = PR_LoadProgs(menu_world.progs, "menu.dat", 10020, NULL, 0); if (mprogs < 0) //no per-progs builtins. { @@ -2057,6 +2077,16 @@ void MP_Reload_f(void) M_Reinit(); } +static void MP_Poke_f(void) +{ + if (!SV_MayCheat()) + Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n"); + else if (svprogfuncs && svprogfuncs->EvaluateDebugString) + Con_TPrintf("Result: %s\n", svprogfuncs->EvaluateDebugString(svprogfuncs, Cmd_Args())); + else + Con_TPrintf ("not supported.\n"); +} + void MP_Breakpoint_f(void) { int wasset; @@ -2090,6 +2120,9 @@ void MP_RegisterCvarsAndCmds(void) Cmd_AddCommand("breakpoint_menu", MP_Breakpoint_f); Cmd_AddCommand("loadfont", CL_LoadFont_f); + Cmd_AddCommand("poke_menuqc", MP_Poke_f); + + Cvar_Register(&forceqmenu, MENUPROGSGROUP); Cvar_Register(&pr_menuqc_coreonerror, MENUPROGSGROUP); diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 3e83eef2..197063c9 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -833,9 +833,9 @@ void R2D_Console_Resize(void) if (!cwidth && !cheight) cheight = 480; - if (cheight && !cwidth) + if (cheight && !cwidth && vid.rotpixelheight) cwidth = (cheight*vid.rotpixelwidth)/vid.rotpixelheight; - if (cwidth && !cheight) + if (cwidth && !cheight && vid.rotpixelwidth) cheight = (cwidth*vid.rotpixelheight)/vid.rotpixelwidth; if (!cwidth) diff --git a/engine/client/render.h b/engine/client/render.h index fd066f66..e384cbd2 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -341,8 +341,6 @@ enum imageflags /*warning: many of these flags only apply the first time it is requested*/ IF_CLAMP = 1<<0, IF_NEAREST = 1<<1, - IF_UIPIC = 1<<10, //subject to texturemode2d - IF_LINEAR = 1<<11, IF_NOPICMIP = 1<<2, IF_NOMIPMAP = 1<<3, IF_NOALPHA = 1<<4, @@ -353,6 +351,9 @@ enum imageflags IF_TEXTYPE = (1<<6) | (1<<7) | (1<<8), /*0=2d, 1=3d, 2-7=cubeface*/ IF_TEXTYPESHIFT = 6, /*0=2d, 1=3d, 2-7=cubeface*/ IF_MIPCAP = 1<<9, + IF_UIPIC = 1<<10, //subject to texturemode2d + IF_LINEAR = 1<<11, + IF_PREMULTIPLYALPHA = 1<<12, //rgb *= alpha IF_EXACTEXTENSION = 1<<29, IF_REPLACE = 1<<30, IF_SUBDIRONLY = 1<<31 @@ -433,10 +434,10 @@ void Mod_NowLoadExternal(void); void GLR_LoadSkys (void); void R_BloomRegister(void); -int Mod_RegisterModelFormatText(void *module, const char *formatname, char *magictext, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)); -int Mod_RegisterModelFormatMagic(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)); -void Mod_UnRegisterModelFormat(int idx); -void Mod_UnRegisterAllModelFormats(void *module); +int QDECL Mod_RegisterModelFormatText(void *module, const char *formatname, char *magictext, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)); +int QDECL Mod_RegisterModelFormatMagic(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)); +void QDECL Mod_UnRegisterModelFormat(int idx); +void QDECL Mod_UnRegisterAllModelFormats(void *module); #ifdef RUNTIMELIGHTING void LightFace (int surfnum); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index e910664a..d32b9735 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -857,6 +857,7 @@ rendererinfo_t d3d11rendererinfo; #ifdef SWQUAKE rendererinfo_t swrendererinfo; #endif +rendererinfo_t headlessrenderer; rendererinfo_t *rendererinfo[] = { @@ -879,6 +880,7 @@ rendererinfo_t *rendererinfo[] = #ifndef NPQTV &dedicatedrendererinfo, #endif + &headlessrenderer, }; @@ -1017,6 +1019,7 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr) extern model_t *loadmodel; Cache_Flush(); + COM_FlushFSCache(); //make sure the fs cache is built if needed. there's lots of loading here. TRACE(("dbg: R_ApplyRenderer: old renderer closed\n")); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 10c78d05..9c6dd6e4 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -816,6 +816,8 @@ void Sbar_Start (void) //if one of these fails, skip the entire status bar. } failedpic = false; + COM_FlushFSCache(); //make sure the fs cache is built if needed. there's lots of loading here. + sbarfailed = false; for (i=0 ; i<10 ; i++) diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index e1382691..bf7b03ec 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -574,7 +574,7 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI GLVID_Crashed(); #endif - if (!iswatchdog && pIsDebuggerPresent ()) + if (!iswatchdog && pIsDebuggerPresent && pIsDebuggerPresent ()) { /*if we have a current window, minimize it to bring us out of fullscreen*/ extern qboolean vid_initializing; diff --git a/engine/client/vid.h b/engine/client/vid.h index 978a834a..48ad32bb 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // a pixel can be one, two, or four bytes typedef qbyte pixel_t; -typedef enum {QR_NONE, QR_OPENGL, QR_DIRECT3D9, QR_DIRECT3D11, QR_SOFTWARE} r_qrenderer_t; +typedef enum {QR_NONE, QR_HEADLESS, QR_OPENGL, QR_DIRECT3D9, QR_DIRECT3D11, QR_SOFTWARE} r_qrenderer_t; typedef struct { //you are not allowed to make anything not work if it's not based on these vars... diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 4d6daafb..a5465daa 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -633,7 +633,7 @@ uses parent bone info, so don't try to offset for a first bone. ALWAYS writes dest. Don't force it if you don't want to waste cycles when no conversion is actually needed. destbonecount is to catch errors, its otherwise ignored for now. no identity padding. */ -void Alias_ForceConvertBoneData(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount) +void QDECL Alias_ForceConvertBoneData(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount) { float altbuffer[MAX_BONES*12]; const float *buf = Alias_ConvertBoneData(sourcetype, sourcedata, bonecount, bones, desttype, destbuffer, altbuffer, destbonecount); diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index c836234d..8acff65f 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -164,27 +164,27 @@ typedef struct galiasinfo_s typedef struct { - int (*RegisterModelFormatText)(void *module, const char *formatname, char *magictext, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)); - int (*RegisterModelFormatMagic)(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)); - void (*UnRegisterModelFormat)(int idx); - void (*UnRegisterAllModelFormats)(void *module); + int (QDECL *RegisterModelFormatText)(void *module, const char *formatname, char *magictext, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)); + int (QDECL *RegisterModelFormatMagic)(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)); + void (QDECL *UnRegisterModelFormat)(int idx); + void (QDECL *UnRegisterAllModelFormats)(void *module); - void *(*ZG_Malloc)(zonegroup_t *ctx, int size); + void *(QDECL *ZG_Malloc)(zonegroup_t *ctx, int size); - void (*ConcatTransforms) (float in1[3][4], float in2[3][4], float out[3][4]); - void (*M3x4_Invert) (const float *in1, float *out); - void (*StripExtension) (const char *in, char *out, int outlen); - void (*GenMatrixPosQuat4Scale)(vec3_t pos, vec4_t quat, vec3_t scale, float result[12]); - void (*ForceConvertBoneData)(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount); + void (QDECL *ConcatTransforms) (float in1[3][4], float in2[3][4], float out[3][4]); + void (QDECL *M3x4_Invert) (const float *in1, float *out); + void (QDECL *StripExtension) (const char *in, char *out, int outlen); + void (QDECL *GenMatrixPosQuat4Scale)(vec3_t pos, vec4_t quat, vec3_t scale, float result[12]); + void (QDECL *ForceConvertBoneData)(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount); - shader_t *(*RegisterShader) (const char *name, unsigned int usageflags, const char *shaderscript); - shader_t *(*RegisterSkin) (const char *shadername, const char *modname); - void (*BuildDefaultTexnums)(texnums_t *tn, shader_t *shader); + shader_t *(QDECL *RegisterShader) (const char *name, unsigned int usageflags, const char *shaderscript); + shader_t *(QDECL *RegisterSkin) (const char *shadername, const char *modname); + void (QDECL *BuildDefaultTexnums)(texnums_t *tn, shader_t *shader); } modplugfuncs_t; #ifdef SKELETALMODELS void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout); -void Alias_ForceConvertBoneData(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount); +void QDECL Alias_ForceConvertBoneData(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount); #endif qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, int surfnum, entity_t *e, qboolean allowskel); void Alias_FlushCache(void); diff --git a/engine/common/common.c b/engine/common/common.c index 59e056fa..0640bb8b 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1759,7 +1759,7 @@ char *COM_SkipPath (const char *pathname) COM_StripExtension ============ */ -void COM_StripExtension (const char *in, char *out, int outlen) +void QDECL COM_StripExtension (const char *in, char *out, int outlen) { char *s; diff --git a/engine/common/common.h b/engine/common/common.h index 96abbb57..53a339c4 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -317,7 +317,7 @@ size_t unicode_strtoupper(const char *in, char *out, size_t outsize, qboolean ma unsigned int unicode_charcount(const char *in, size_t buffersize, qboolean markup); char *COM_SkipPath (const char *pathname); -void COM_StripExtension (const char *in, char *out, int outlen); +void QDECL COM_StripExtension (const char *in, char *out, int outlen); void COM_StripAllExtensions (char *in, char *out, int outlen); void COM_FileBase (const char *in, char *out, int outlen); int QDECL COM_FileSize(const char *path); diff --git a/engine/common/console.h b/engine/common/console.h index 4a7c0a28..64eef2e0 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -198,6 +198,7 @@ void Con_ExecuteLine(console_t *con, char *line); //takes normal console command void Con_CycleConsole (void); int Con_IsActive (console_t *con); void Con_Destroy (console_t *con); +void Con_ClearCon(console_t *con); void Con_SetActive (console_t *con); qboolean Con_NameForNum(int num, char *buffer, int buffersize); console_t *Con_FindConsole(const char *name); diff --git a/engine/common/fs.c b/engine/common/fs.c index 635749c0..5fbb2dda 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -2299,7 +2299,7 @@ void COM_Gamedir (const char *dir) #define QCFG "set allow_download_refpackages 0\n" /*stuff that makes dp-only mods work a bit better*/ -#define DPCOMPAT QCFG "set _cl_playermodel \"\"\n set dpcompat_set 1\n set dpcompat_trailparticles 1\nset dpcompat_corruptglobals 1\nset vid_pixelheight 1\n" +#define DPCOMPAT QCFG "set _cl_playermodel \"\"\n set dpcompat_set 1\nset dpcompat_corruptglobals 1\nset vid_pixelheight 1\n" /*nexuiz/xonotic has a few quirks/annoyances...*/ #define NEXCFG DPCOMPAT "set r_particlesdesc effectinfo\nset sv_bigcoords 1\nset sv_maxairspeed \"400\"\nset sv_jumpvelocity 270\nset sv_mintic \"0.01\"\ncl_nolerp 0\npr_enable_uriget 0\n" /*some modern non-compat settings*/ diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index bbd7f102..46dc0c88 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -579,7 +579,7 @@ void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]) R_ConcatTransforms ================ */ -void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +void QDECL R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) { out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; @@ -757,7 +757,7 @@ void VectorTransform (const vec3_t in1, const matrix3x4 in2, vec3_t out) out[2] = DotProduct(in1, in2[2]) + in2[2][3]; } -void GenMatrixPosQuat4Scale(vec3_t pos, vec4_t quat, vec3_t scale, float result[12]) +void QDECL GenMatrixPosQuat4Scale(vec3_t pos, vec4_t quat, vec3_t scale, float result[12]) { float xx, xy, xz, xw, yy, yz, yw, zz, zw; float x2, y2, z2; @@ -1635,7 +1635,7 @@ void Matrix3x4_Invert (const float *in1, float *out) Vector4Set (out+8, c[0], c[1], c[2], -DotProduct (c, trans)); } -void Matrix3x4_Invert_Simple (const float *in1, float *out) +void QDECL Matrix3x4_Invert_Simple (const float *in1, float *out) { // we only support uniform scaling, so assume the first row is enough // (note the lack of sqrt here, because we're trying to undo the scaling, diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 87e9e28b..73d1478b 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -155,7 +155,7 @@ void Matrix3_Multiply (vec3_t *in1, vec3_t *in2, vec3_t *out); void Matrix4x4_Identity(float *outm); qboolean Matrix4_Invert(const float *m, float *out); void Matrix3x4_Invert (const float *in1, float *out); -void Matrix3x4_Invert_Simple (const float *in1, float *out); +void QDECL Matrix3x4_Invert_Simple (const float *in1, float *out); void Matrix3x4_InvertTo4x4_Simple (const float *in1, float *out); void Matrix3x3_RM_Invert_Simple(const vec3_t in[3], vec3_t out[3]); void Matrix4x4_RM_CreateTranslate (float *out, float x, float y, float z); @@ -182,7 +182,7 @@ void Matrix3x4_RM_Transform3(const float *matrix, const float *vector, float *p float *Matrix4x4_CM_NewRotation(float a, float x, float y, float z); float *Matrix4x4_CM_NewTranslation(float x, float y, float z); -void GenMatrixPosQuat4Scale(vec3_t pos, vec4_t quat, vec3_t scale, float result[12]); +void QDECL GenMatrixPosQuat4Scale(vec3_t pos, vec4_t quat, vec3_t scale, float result[12]); #define AngleVectorsFLU(a,f,l,u) do{AngleVectors(a,f,l,u);VectorNegate(l,l);}while(0) @@ -202,7 +202,7 @@ fixed16_t Mul16_30 (fixed16_t multiplier, fixed16_t multiplicand); int Q_log2 (int val); void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); void R_ConcatRotationsPad (float in1[3][4], float in2[3][4], float out[3][4]); -void R_ConcatTransforms (matrix3x4 in1, matrix3x4 in2, matrix3x4 out); +void QDECL R_ConcatTransforms (matrix3x4 in1, matrix3x4 in2, matrix3x4 out); void RotatePointAroundVector (vec3_t dst, const vec3_t dir, const vec3_t point, float degrees); void RotateLightVector(const vec3_t *axis, const vec3_t origin, const vec3_t lightpoint, vec3_t result); int VectorCompare (const vec3_t v1, const vec3_t v2); diff --git a/engine/common/particles.h b/engine/common/particles.h index 4bcc765a..741bc835 100644 --- a/engine/common/particles.h +++ b/engine/common/particles.h @@ -77,7 +77,7 @@ typedef struct trailstate_s { #define PARTICLE_Z_CLIP 8.0 -typedef enum { BM_BLEND, BM_BLENDCOLOUR, BM_ADDA, BM_ADDC, BM_SUBTRACT, BM_INVMODA, BM_INVMODC } blendmode_t; +typedef enum { BM_BLEND/*SRC_ALPHA ONE_MINUS_SRC_ALPHA*/, BM_BLENDCOLOUR/*SRC_COLOR ONE_MINUS_SRC_COLOR*/, BM_ADDA/*SRC_ALPHA ONE*/, BM_ADDC/*GL_SRC_COLOR GL_ONE*/, BM_SUBTRACT/*SRC_ALPHA ONE_MINUS_SRC_COLOR*/, BM_INVMODA/*ZERO ONE_MINUS_SRC_ALPHA*/, BM_INVMODC/*ZERO ONE_MINUS_SRC_COLOR*/, BM_PREMUL/*ONE ONE_MINUS_SRC_ALPHA*/} blendmode_t; #define frandom() (rand()*(1.0f/RAND_MAX)) #define crandom() (rand()*(2.0f/RAND_MAX)-1.0f) diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 77035963..e9a20c27 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -16,10 +16,11 @@ static char *cvargroup_progs = "Progs variables"; cvar_t sv_gameplayfix_blowupfallenzombies = CVARD("sv_gameplayfix_blowupfallenzombies", "0", "Allow findradius to find non-solid entities. This may break certain mods."); cvar_t pr_droptofloorunits = CVAR("pr_droptofloorunits", ""); -cvar_t pr_brokenfloatconvert = SCVAR("pr_brokenfloatconvert", "0"); -cvar_t pr_tempstringcount = SCVAR("pr_tempstringcount", "");//"16"); -cvar_t pr_tempstringsize = SCVAR("pr_tempstringsize", "4096"); -cvar_t pr_enable_uriget = SCVAR("pr_enable_uriget", "1"); +cvar_t pr_brokenfloatconvert = CVAR("pr_brokenfloatconvert", "0"); +cvar_t pr_tempstringcount = CVAR("pr_tempstringcount", "");//"16"); +cvar_t pr_tempstringsize = CVAR("pr_tempstringsize", "4096"); +cvar_t pr_enable_uriget = CVAR("pr_enable_uriget", "1"); +cvar_t pr_enable_profiling = CVARD("pr_enable_profiling", "0", "Enables profiling support. Will run more slowly. Change the map and then use the profile_ssqc/profile_csqc commands to see the results."); int tokenizeqc(const char *str, qboolean dpfuckage); void skel_info_f(void); @@ -32,6 +33,7 @@ void PF_Common_RegisterCvars(void) Cvar_Register (&pr_tempstringcount, cvargroup_progs); Cvar_Register (&pr_tempstringsize, cvargroup_progs); Cvar_Register (&pr_enable_uriget, cvargroup_progs); + Cvar_Register (&pr_enable_profiling, cvargroup_progs); #ifdef RAGDOLL Cmd_AddCommand("skel_info", skel_info_f); @@ -5092,10 +5094,11 @@ lh_extension_t QSG_Extensions[] = { {"FTE_CSQC_SKELETONOBJECTS", 15, NULL, { "skel_create", "skel_build", "skel_get_numbones", "skel_get_bonename", "skel_get_boneparent", "skel_find_bone", "skel_get_bonerel", "skel_get_boneabs", "skel_set_bone", "skel_mul_bone", "skel_mul_bones", "skel_copybones", "skel_delete", "frameforname", "frameduration"}}, + {"FTE_CSQC_RENDERTARGETS_WIP"}, {"FTE_ENT_SKIN_CONTENTS"}, //self.skin = CONTENTS_WATER; makes a brush entity into water. use -16 for a ladder. {"FTE_ENT_UNIQUESPAWNID"}, {"FTE_EXTENDEDTEXTCODES"}, - {"FTE_FORCESHADER", 1, NULL, {"shaderforname"}}, + {"FTE_FORCESHADER", 1, NULL, {"shaderforname"}}, //I'd rename this to _CSQC_ but it does technically provide this builtin to menuqc too, not that the forceshader entity field exists there... but whatever. {"FTE_FORCEINFOKEY", 1, NULL, {"forceinfokey"}}, {"FTE_GFX_QUAKE3SHADERS"}, {"FTE_ISBACKBUFFERED", 1, NULL, {"isbackbuffered"}}, diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index aef8d0df..46771e48 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -83,6 +83,7 @@ char *PF_TempStr(pubprogfuncs_t *prinst); //returns a tempstring which can be fi #define RETURN_TSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_TempString(prinst, s)) //temp (static but cycle buffers) extern cvar_t pr_tempstringsize; extern cvar_t pr_tempstringcount; +extern cvar_t pr_enable_profiling; extern int qcinput_scan; extern int qcinput_unicode; diff --git a/engine/common/protocol.h b/engine/common/protocol.h index fbfd7da8..5aea14cf 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -1558,9 +1558,9 @@ typedef struct q1usercmd_s // unused #define E5_GLOWMOD (1<<24) // unused -#define E5_UNUSED25 (1<<25) +#define E5_COMPLEXANIMATION (1<<25) // unused -#define E5_UNUSED26 (1<<26) +#define E5_TRAILEFFECTNUM (1<<26) // unused #define E5_UNUSED27 (1<<27) // unused @@ -1572,4 +1572,4 @@ typedef struct q1usercmd_s // bits2 > 0 #define E5_EXTEND4 (1<<31) -#define E5_ALLUNUSED (E5_UNUSED25|E5_UNUSED26|E5_UNUSED27|E5_UNUSED28|E5_UNUSED29|E5_UNUSED30) +#define E5_ALLUNUSED (E5_COMPLEXANIMATION|E5_UNUSED27|E5_UNUSED28|E5_UNUSED29|E5_UNUSED30) diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 3936fd5c..63d4d36b 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -1500,7 +1500,7 @@ int Q1BSP_ClipDecal(vec3_t center, vec3_t normal, vec3_t tangent1, vec3_t tangen #endif #ifdef TERRAIN - if (cl.worldmodel->terrain) + if (cl.worldmodel && cl.worldmodel->terrain) Terrain_ClipDecal(&dec, center, dec.radius, cl.worldmodel); #endif diff --git a/engine/common/zone.c b/engine/common/zone.c index 45769db3..9be47dd3 100644 --- a/engine/common/zone.c +++ b/engine/common/zone.c @@ -457,10 +457,10 @@ typedef struct zonegroupblock_s #ifdef USE_MSVCRT_DEBUG #undef ZG_Malloc -void *ZG_Malloc(zonegroup_t *ctx, int size){return ZG_MallocNamed(ctx, size, "ZG_Malloc", size);} +void *QDECL ZG_Malloc(zonegroup_t *ctx, int size){return ZG_MallocNamed(ctx, size, "ZG_Malloc", size);} void *ZG_MallocNamed(zonegroup_t *ctx, int size, char *file, int line) #else -void *ZG_Malloc(zonegroup_t *ctx, int size) +void *QDECL ZG_Malloc(zonegroup_t *ctx, int size) #endif { zonegroupblock_t *newm; diff --git a/engine/common/zone.h b/engine/common/zone.h index a64cf703..099cde29 100644 --- a/engine/common/zone.h +++ b/engine/common/zone.h @@ -115,7 +115,7 @@ typedef struct zonegroup_s void *first; int bytes; } zonegroup_t; -void *ZG_Malloc(zonegroup_t *ctx, int size); +void *QDECL ZG_Malloc(zonegroup_t *ctx, int size); void *ZG_MallocNamed(zonegroup_t *ctx, int size, char *file, int line); void ZG_FreeGroup(zonegroup_t *ctx); diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index a6f9f711..a6df87cf 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -22754,6 +22754,10 @@ /> + + diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 0a66898e..dd224041 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -281,7 +281,8 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext) { Q_strncpyz(skin->mappings[skin->nummappings].surface, com_token, sizeof(skin->mappings[skin->nummappings].surface)); skintext = COM_ParseToken(skintext+1, NULL); - skin->mappings[skin->nummappings].shader = R_RegisterSkin(com_token, skin->skinname); + Q_strncpyz(shadername, com_token, sizeof(shadername)); + skin->mappings[skin->nummappings].shader = R_RegisterSkin(shadername, skin->skinname); R_BuildDefaultTexnums(NULL, skin->mappings[skin->nummappings].shader); skin->mappings[skin->nummappings].texnums = skin->mappings[skin->nummappings].shader->defaulttextures; skin->nummappings++; diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 6007b13f..e2a20c6c 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -1321,7 +1321,7 @@ static void GL_Upload32_Int (const char *name, unsigned *data, int width, int he qglTexImage2D (targface, 0, samples, scaled_width, scaled_height, 0, glcolormode, GL_UNSIGNED_BYTE, data); else if (scaled_width == width && scaled_height == height) { - if ((flags&IF_NOMIPMAP)||gl_config.sgis_generate_mipmap) //gotta love this with NPOT textures... :) + if (((flags&IF_NOMIPMAP)||gl_config.sgis_generate_mipmap) && !(flags & IF_PREMULTIPLYALPHA)) //gotta love this with NPOT textures... :) { TRACE(("dbg: GL_Upload32: non-mipmapped/unscaled\n")); if (type == GL_UNSIGNED_SHORT_5_6_5) @@ -1336,6 +1336,19 @@ static void GL_Upload32_Int (const char *name, unsigned *data, int width, int he } else GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); + + if (flags & IF_PREMULTIPLYALPHA) + { + //works for rgba or bgra + int i; + unsigned char *premul = (unsigned char*)scaled; + for (i = 0; i < scaled_width*scaled_height; i++, premul+=4) + { + premul[0] = (premul[0] * premul[3])>>8; + premul[1] = (premul[1] * premul[3])>>8; + premul[2] = (premul[2] * premul[3])>>8; + } + } if (scaled_width * scaled_height*4 > sizeofuploadmemorybufferintermediate) { sizeofuploadmemorybufferintermediate = scaled_width * scaled_height * 4; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 77f909e6..26d9421d 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -715,7 +715,7 @@ static struct qboolean (QDECL *load) (model_t *mod, void *buffer, size_t buffersize); } modelloaders[64]; -int Mod_RegisterModelFormatText(void *module, const char *formatname, char *magictext, qboolean (QDECL *load) (model_t *mod, void *buffer, size_t fsize)) +int QDECL Mod_RegisterModelFormatText(void *module, const char *formatname, char *magictext, qboolean (QDECL *load) (model_t *mod, void *buffer, size_t fsize)) { int i, free = -1; for (i = 0; i < sizeof(modelloaders)/sizeof(modelloaders[0]); i++) @@ -739,7 +739,7 @@ int Mod_RegisterModelFormatText(void *module, const char *formatname, char *magi return free+1; } -int Mod_RegisterModelFormatMagic(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (model_t *mod, void *buffer, size_t fsize)) +int QDECL Mod_RegisterModelFormatMagic(void *module, const char *formatname, unsigned int magic, qboolean (QDECL *load) (model_t *mod, void *buffer, size_t fsize)) { int i, free = -1; for (i = 0; i < sizeof(modelloaders)/sizeof(modelloaders[0]); i++) @@ -766,7 +766,7 @@ int Mod_RegisterModelFormatMagic(void *module, const char *formatname, unsigned return free+1; } -void Mod_UnRegisterModelFormat(int idx) +void QDECL Mod_UnRegisterModelFormat(int idx) { idx--; if ((unsigned int)(idx) >= sizeof(modelloaders)/sizeof(modelloaders[0])) @@ -783,7 +783,7 @@ void Mod_UnRegisterModelFormat(int idx) //FS_Restart will be needed } -void Mod_UnRegisterAllModelFormats(void *module) +void QDECL Mod_UnRegisterAllModelFormats(void *module) { int i; for (i = 0; i < sizeof(modelloaders)/sizeof(modelloaders[0]); i++) diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index ee624bb7..8e99466a 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -282,6 +282,7 @@ void R_RenderDlights (void) float intensity, cscale; qboolean coronastyle; qboolean flashstyle; + float dist; if (!r_coronas.value && !r_flashblend.value) return; @@ -321,6 +322,16 @@ void R_RenderDlights (void) if (intensity <= 0 || cscale <= 0) continue; + //prevent the corona from intersecting with the near clip plane by just fading it away if its too close + VectorSubtract(l->origin, r_refdef.vieworg, waste1); + dist = VectorLength(waste1); + if (dist < 128+256) + { + if (dist <= 128) + continue; + intensity *= (dist-128) / 256; + } + /*coronas use depth testing to compute visibility*/ if (coronastyle) { diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index e6dc1b8e..95681194 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -3854,7 +3854,7 @@ void Shader_UpdateRegistration (void) } */ -void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) +void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) { char *h; char imagename[MAX_QPATH]; @@ -5145,7 +5145,7 @@ shader_t *R_RegisterPic (const char *name) return shader; } -shader_t *R_RegisterShader (const char *name, unsigned int usageflags, const char *shaderscript) +shader_t *QDECL R_RegisterShader (const char *name, unsigned int usageflags, const char *shaderscript) { return R_LoadShader (name, usageflags, Shader_DefaultScript, shaderscript); } @@ -5165,7 +5165,7 @@ shader_t *R_RegisterShader_Flare (const char *name) return R_LoadShader (name, 0, Shader_DefaultBSPFlare, NULL); } -shader_t *R_RegisterSkin (const char *shadername, const char *modname) +shader_t *QDECL R_RegisterSkin (const char *shadername, const char *modname) { shader_t *shader; #ifdef _DEBUG diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 98213fb6..d87d1374 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -555,13 +555,13 @@ extern int be_maxpasses; void R_UnloadShader(shader_t *shader); shader_t *R_RegisterPic (const char *name); -shader_t *R_RegisterShader (const char *name, unsigned int usageflags, const char *shaderscript); +shader_t *QDECL R_RegisterShader (const char *name, unsigned int usageflags, const char *shaderscript); shader_t *R_RegisterShader_Lightmap (const char *name); shader_t *R_RegisterShader_Vertex (const char *name); shader_t *R_RegisterShader_Flare (const char *name); -shader_t *R_RegisterSkin (const char *shadername, const char *modname); +shader_t *QDECL R_RegisterSkin (const char *shadername, const char *modname); shader_t *R_RegisterCustom (const char *name, unsigned int usageflags, shader_gen_t *defaultgen, const void *args); -void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader); +void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader); void R_RemapShader(const char *sourcename, const char *destname, float timeoffset); cin_t *R_ShaderGetCinematic(shader_t *s); diff --git a/engine/partcfgs/high.cfg b/engine/partcfgs/high.cfg index 3b8955af..4b4cd7c6 100644 --- a/engine/partcfgs/high.cfg +++ b/engine/partcfgs/high.cfg @@ -194,6 +194,34 @@ r_part +te_spike assoc gunshotsmoke } +r_part te_superspike +{ + type sparkfan + count 20 + scale 1 + scalefactor 1 + alpha 0.5 + die 0.2 + rgb 255 128 0 + blend add + spawnmode ball + spawnorg 12 + spawnvel 300 +} +r_part +te_superspike +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + count 1 + scale 1 + scalefactor 1 + scaledelta 190 + die 0.1 + alpha 0.6 + rgb 255 128 0 + blend add + assoc gunshotsmoke +} //////////////////////////////////////////////// //explosion @@ -262,9 +290,10 @@ r_part +te_explosion //hide lights in explosions. //r_explosionlight 0 -//hide the explosion sprite in nq+qw - WARNING: some mods use this sprite as a flame thrower. +//hide the explosion sprite in qw cl_expsprite 0 -r_effect "progs/s_explod.spr" hidden 1 +//hide it in nq - WARNING: some mods use this sprite as a flame thrower. +//r_effect "progs/s_explod.spr" hidden 1 ////////////////////////////////////////// //r_part te_tarexplosion @@ -277,6 +306,7 @@ r_effect "progs/s_explod.spr" hidden 1 //} ////////////////////////////////////////// +//FIXME: what if we don't have glsl support? r_part te_teleport { scale 250 @@ -354,6 +384,22 @@ r_part tr_knightspike lightrgb 0.75 0.37 0.18 } +r_part te_knightspike +{ + type sparkfan + count 200 + scale 3 + scalefactor 1 + alpha 0.5 + die 0.5 + rgb 192 96 48 + blend add + spawnmode ball + spawnorg 12 + spawnvel 100 + stretchfactor 10 +} + ///////////////////////////////////////// //vore missiles r_part tr_vorespike @@ -408,13 +454,13 @@ r_part tr_enforcerlaser r_trail "progs/laser.mdl" tr_enforcerlaser ///////////////////////////////////////// -//scrag missiles. just use the default trail cos we're lazy +//scrag missiles. r_part tr_wizspike { texture "particles/fteparticlefont.tga" tcoords 1 97 95 191 256 scale 15 - step 1 + step 4 alpha 0.6 die 0.2 rgb 25 200 25 @@ -425,12 +471,54 @@ r_part tr_wizspike spawnmode spiral spawnvel 25 blend add - lighttime 0 + lighttime 2 + lightradiusfade 75 lightshadows 0 lightradius 150 lightrgb 0.1 0.7 0.1 } +r_part tr_wizspike2 +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 4 + step 1 + alpha 0.6 + die 0.2 + rgb 25 200 25 + veladd 64 + randomvel 64 + friction 4 + scalefactor 0.825 + spawnmode spiral + spawnvel 25 + blend add +} +//scrag impact +r_part te_wizspike +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + alpha 0.6 + rgb 25 200 25 + friction 0 + scalefactor 0.825 + blend add + count 5 + veladd -256 + randomvel 256 + die 1 + diesubrand 0.5 + gravity 800 + emit tr_wizspike2 + emitinterval -1 + bounce 1.5 +} + +///////////////////////////////////////// +//shambler stuff r_part shambercharging { spawnmode ball @@ -456,7 +544,8 @@ r_part shambercharging } r_effect progs/s_light.mdl shambercharging 0 - +///////////////////////////////////////// +//blood effects r_part te_blood { texture fte_bloodparticle diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index de0fceb1..071ff9b0 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -14,7 +14,6 @@ #if INTSIZE == 16 #define cont cont16 #define reeval reeval16 -#define st st16 #define pr_statements pr_statements16 #define fakeop fakeop16 #define dstatement_t dstatement16_t @@ -23,7 +22,6 @@ #elif INTSIZE == 32 #define cont cont32 #define reeval reeval32 -#define st st32 #define pr_statements pr_statements32 #define fakeop fakeop32 #define dstatement_t dstatement32_t @@ -44,8 +42,8 @@ #define ENGINEPOINTER(p) ((char*)(p) - progfuncs->funcs.stringtable) #define QCPOINTER(p) (eval_t *)(p->_int+progfuncs->funcs.stringtable) #define QCPOINTERM(p) (eval_t *)((p)+progfuncs->funcs.stringtable) -#define QCPOINTERWRITEFAIL(p) ((unsigned int)p->_int-1 >= prinst.addressableused-1) //disallows null writes -#define QCPOINTERREADFAIL(p) ((unsigned int)p->_int >= prinst.addressableused) //permits null writes +#define QCPOINTERWRITEFAIL(p,sz) ((unsigned int)p->_int-1 >= prinst.addressableused-1-sz) //disallows null writes +#define QCPOINTERREADFAIL(p,sz) ((unsigned int)p->_int >= prinst.addressableused-sz) //permits null reads //rely upon just st { @@ -80,6 +78,7 @@ cont: //last statement may have been a breakpoint if (progfuncs->funcs.pr_trace) s=ShowStep(progfuncs, s); st = pr_statements + s; + pr_xfunction->profile+=1; reeval: #else @@ -324,8 +323,10 @@ reeval: //store a value to a pointer case OP_STOREP_IF: - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { + if (OPB->_int == -1) + break; pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); } @@ -333,8 +334,10 @@ reeval: ptr->_float = (float)OPA->_int; break; case OP_STOREP_FI: - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(int))) { + if (OPB->_int == -1) + break; pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); } @@ -347,8 +350,10 @@ reeval: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(int))) { + if (OPB->_int == -1) + break; pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } @@ -356,8 +361,10 @@ reeval: ptr->_int = OPA->_int; break; case OP_STOREP_V: - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(vec3_t))) { + if (OPB->_int == -1) + break; pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } @@ -368,7 +375,7 @@ reeval: break; case OP_STOREP_C: //store character in a string - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(char))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); @@ -387,7 +394,7 @@ reeval: OPB->_vector[2] *= tmpf; break; case OP_MULSTOREP_F: // e.f *= f - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); @@ -396,7 +403,7 @@ reeval: OPC->_float = (ptr->_float *= OPA->_float); break; case OP_MULSTOREP_VF: // e.v *= f - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(vec3_t))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); @@ -412,7 +419,7 @@ reeval: OPB->_float /= OPA->_float; break; case OP_DIVSTOREP_F: // e.f /= f - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); @@ -430,7 +437,7 @@ reeval: OPB->_vector[2] += OPA->_vector[2]; break; case OP_ADDSTOREP_F: // e.f += f - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); @@ -439,7 +446,7 @@ reeval: OPC->_float = (ptr->_float += OPA->_float); break; case OP_ADDSTOREP_V: // e.v += v - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(vec3_t))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); @@ -459,7 +466,7 @@ reeval: OPB->_vector[2] -= OPA->_vector[2]; break; case OP_SUBSTOREP_F: // e.f -= f - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); @@ -468,7 +475,7 @@ reeval: OPC->_float = (ptr->_float -= OPA->_float); break; case OP_SUBSTOREP_V: // e.v -= v - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(vec3_t))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); @@ -511,6 +518,8 @@ reeval: st--; goto cont; } + OPC->_int = ~0; + break; } } @@ -855,7 +864,7 @@ reeval: break; case OP_LOADP_C: //load character from a string i = (unsigned int)OPA->_int + (unsigned int)OPB->_float; - if ((unsigned int)i >= prinst.addressableused) + if ((unsigned int)i > prinst.addressableused-sizeof(char)) { i = (unsigned int)OPB->_float; ptr = (eval_t*)PR_StringToNative(&progfuncs->funcs, OPA->_int); @@ -877,8 +886,10 @@ reeval: case OP_LOADP_S: case OP_LOADP_FNC: i = OPA->_int + OPB->_int*4; - if ((unsigned int)i >= prinst.addressableused) + if ((unsigned int)i > prinst.addressableused-sizeof(int)) { + if (i == -1) + break; pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer read in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); } @@ -888,8 +899,10 @@ reeval: case OP_LOADP_V: i = OPA->_int + OPB->_int*4; - if ((unsigned int)i >= prinst.addressableused) + if ((unsigned int)i > prinst.addressableused-sizeof(vec3_t)) { + if (i == -1) + break; pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer read in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); } @@ -952,7 +965,7 @@ reeval: OPB->_float = (float)((int)OPB->_float | (int)OPA->_float); break; case OP_BITSETSTOREP_F: // .b (+) a - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); @@ -964,7 +977,7 @@ reeval: OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float)); break; case OP_BITCLRSTOREP_F: // .b (-) a - if (QCPOINTERWRITEFAIL(OPB)) + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); @@ -1170,7 +1183,7 @@ reeval: case OP_GADDRESS: //return glob[aint+bfloat] //this instruction is not implemented due to the weirdness of it. //its theoretically a more powerful load... but untyped? - //or is it meant to be an LEA instruction (that could simply be switched with + //or is it meant to be an LEA instruction (that could simply be switched with OP_GLOAD_I) pr_xstatement = st-pr_statements; PR_RunError (&progfuncs->funcs, "OP_GADDRESS not implemented (found in %s)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); break; @@ -1183,7 +1196,7 @@ reeval: if (OPA->_int < 0 || OPA->_int*4 >= current_progstate->globals_size) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPA->_int, current_progstate->globals_size); } ptr = ((eval_t *)&glob[OPA->_int]); OPC->_int = ptr->_int; @@ -1192,7 +1205,7 @@ reeval: if (OPA->_int < 0 || (OPA->_int+2)*4 >= current_progstate->globals_size) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPA->_int, current_progstate->globals_size); } ptr = ((eval_t *)&glob[OPA->_int]); OPC->_vector[0] = ptr->_vector[0]; diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index 4ddc07a0..71499f39 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -215,7 +215,7 @@ static void *PDECL PR_memalloc (pubprogfuncs_t *ppf, unsigned int size) b = prinst.mfreelist; while (b) { - if (b < 0 || b >= prinst.addressableused) + if (b < 0 || b+sizeof(qcmemfreeblock_t) >= prinst.addressableused) { printf("PF_memalloc: memory corruption\n"); PR_StackTrace(&progfuncs->funcs); @@ -458,7 +458,7 @@ int PDECL PR_InitEnts(pubprogfuncs_t *ppf, int max_ents) edictrun_t tempedict; //used as a safty buffer static float tempedictfields[2048]; -void PDECL PR_Configure (pubprogfuncs_t *ppf, size_t addressable_size, int max_progs) //can be used to wipe all memory +static void PDECL PR_Configure (pubprogfuncs_t *ppf, size_t addressable_size, int max_progs, pbool profiling) //can be used to wipe all memory { progfuncs_t *progfuncs = (progfuncs_t*)ppf; unsigned int i; @@ -505,6 +505,7 @@ void PDECL PR_Configure (pubprogfuncs_t *ppf, size_t addressable_size, int max_p prinst.reorganisefields = false; + prinst.profiling = profiling; maxedicts = 1; prinst.edicttable = &sv_edicts; sv_num_edicts = 1; //set up a safty buffer so things won't go horribly wrong too often @@ -1023,6 +1024,58 @@ void PR_FreeTemps (progfuncs_t *progfuncs, int depth) prinst.numtempstrings = depth; } +pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf) +{ + progfuncs_t *progfuncs = (progfuncs_t*)ppf; + struct progstate_s *ps; + unsigned int i, f, j, s; + struct + { + char *fname; + int profile; + } *sorted, t; + if (!prinst.profiling) + { + printf("Enabling profiling\n"); + return true; + } + + for (i = 0; i < maxprogs; i++) + { + ps = &pr_progstate[i]; + if (ps->progs == NULL) //we havn't loaded it yet, for some reason + continue; + + printf("%s:\n", ps->filename); + sorted = malloc(sizeof(*sorted) * ps->progs->numfunctions); + //pull out the functions in order to sort them + for (s = 0, f = 0; f < ps->progs->numfunctions; f++) + { + if (!ps->functions[f].profile) + continue; + sorted[s].fname = ps->functions[f].s_name+progfuncs->funcs.stringtable; + sorted[s].profile = ps->functions[f].profile; + ps->functions[f].profile = 0; + s++; + } + + // good 'ol bubble sort + for (f = 0; f < s; f++) + for (j = f; j < s; j++) + if (sorted[f].profile > sorted[j].profile) + { + t = sorted[f]; + sorted[f] = sorted[j]; + sorted[j] = t; + } + + //print it out + for (f = 0; f < s; f++) + printf("%s: %u\n", sorted[f].fname, sorted[f].profile); + free(sorted); + } + return true; +} static void PDECL PR_CloseProgs(pubprogfuncs_t *ppf); @@ -1130,7 +1183,8 @@ pubprogfuncs_t deffuncs = { ED_FieldInfo, PR_UglyValueString, ED_ParseEval, - PR_SetStringField + PR_SetStringField, + PR_DumpProfiles }; static int PDECL qclib_null_printf(const char *s, ...) { diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 5e0b9121..a2a9eeed 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -422,7 +422,7 @@ PR_EnterFunction Returns the new program statement counter ==================== */ -int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, const dfunction_t *f, int progsnum) +int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, dfunction_t *f, int progsnum) { int i, j, c, o; @@ -1176,7 +1176,7 @@ static int PR_ExecuteCode16 (progfuncs_t *fte_restrict progfuncs, int s, int *ft eval_t *t, *swtch=NULL; int swtchtype = 0; //warning about not being initialized before use - dstatement16_t *fte_restrict st16; + const dstatement16_t *fte_restrict st; dfunction_t *fte_restrict newf; int i; edictrun_t *ed; @@ -1191,8 +1191,8 @@ static int PR_ExecuteCode16 (progfuncs_t *fte_restrict progfuncs, int s, int *ft #define OPC ((eval_t *)&glob[st->c]) #define INTSIZE 16 - st16 = &pr_statements16[s]; - while (progfuncs->funcs.pr_trace || prinst.watch_ptr) + st = &pr_statements16[s]; + while (progfuncs->funcs.pr_trace || prinst.watch_ptr || prinst.profiling) { #ifdef FTE_TARGET_WEB //this can generate huge functions, so disable it on systems that can't realiably cope with such things (IE initiates an unwanted denial-of-service attack when pointed our javascript, and firefox prints a warning too) @@ -1223,8 +1223,8 @@ static int PR_ExecuteCode32 (progfuncs_t *fte_restrict progfuncs, int s, int *ft eval_t *t, *swtch=NULL; int swtchtype = 0; //warning about not being initialized before use - const dstatement32_t *fte_restrict st32; - const dfunction_t *fte_restrict newf; + const dstatement32_t *fte_restrict st; + dfunction_t *fte_restrict newf; int i; edictrun_t *ed; eval_t *ptr; @@ -1238,8 +1238,8 @@ static int PR_ExecuteCode32 (progfuncs_t *fte_restrict progfuncs, int s, int *ft #define OPC ((eval_t *)&glob[st->c]) #define INTSIZE 32 - st32 = &pr_statements32[s]; - while (progfuncs->funcs.pr_trace || prinst.watch_ptr) + st = &pr_statements32[s]; + while (progfuncs->funcs.pr_trace || prinst.watch_ptr || prinst.profiling) { #ifdef FTE_TARGET_WEB //this can generate huge functions, so disable it on systems that can't realiably cope with such things (IE initiates an unwanted denial-of-service attack when pointed our javascript, and firefox prints a warning too) @@ -1513,7 +1513,7 @@ struct qcthread_s *PDECL PR_ForkStack(pubprogfuncs_t *ppf) void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread) { progfuncs_t *progfuncs = (progfuncs_t*)ppf; - const dfunction_t *f, *oldf; + dfunction_t *f, *oldf; int i,l,ls; progsnum_t initial_progs; int oldexitdepth; diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index 652eec10..6dbc3670 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -61,7 +61,7 @@ typedef struct sharedvar_s typedef struct { int s; - const dfunction_t *f; + dfunction_t *f; int progsnum; int pushed; } prstack_t; @@ -129,7 +129,8 @@ int reorganisefields; int continuestatement; int exitdepth; - const dfunction_t *pr_xfunction; + pbool profiling; + dfunction_t *pr_xfunction; #define pr_xfunction prinst.pr_xfunction int pr_xstatement; #define pr_xstatement prinst.pr_xstatement @@ -477,7 +478,7 @@ fdef_t *ED_FindField (progfuncs_t *progfuncs, const char *name); fdef_t *ED_FieldAtOfs (progfuncs_t *progfuncs, unsigned int ofs); dfunction_t *ED_FindFunction (progfuncs_t *progfuncs, const char *name, progsnum_t *pnum, progsnum_t fromprogs); func_t PDECL PR_FindFunc(pubprogfuncs_t *progfncs, const char *funcname, progsnum_t pnum); -void PDECL PR_Configure (pubprogfuncs_t *progfncs, size_t addressable_size, int max_progs); +//void PDECL PR_Configure (pubprogfuncs_t *progfncs, size_t addressable_size, int max_progs); int PDECL PR_InitEnts(pubprogfuncs_t *progfncs, int maxents); char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool verbose); void PDECL QC_ClearEdict (pubprogfuncs_t *progfuncs, struct edict_s *ed); diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index d79e3860..93442b8b 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -68,7 +68,7 @@ struct pubprogfuncs_s void (PDECL *CloseProgs) (pubprogfuncs_t *inst); - void (PDECL *Configure) (pubprogfuncs_t *prinst, size_t addressablesize, int max_progs); //configure buffers and memory. Used to reset and must be called first. Flushes a running VM. + void (PDECL *Configure) (pubprogfuncs_t *prinst, size_t addressablesize, int max_progs, pbool enableprofiling); //configure buffers and memory. Used to reset and must be called first. Flushes a running VM. progsnum_t (PDECL *LoadProgs) (pubprogfuncs_t *prinst, const char *s, int headercrc, builtin_t *builtins, int numbuiltins); //load a progs int (PDECL *InitEnts) (pubprogfuncs_t *prinst, int max_ents); //returns size of edicts for use with nextedict macro void (PDECL *ExecuteProgram) (pubprogfuncs_t *prinst, func_t fnum); //start execution @@ -171,6 +171,7 @@ struct pubprogfuncs_s char *(PDECL *UglyValueString) (pubprogfuncs_t *progfuncs, etype_t type, union eval_s *val); pbool (PDECL *ParseEval) (pubprogfuncs_t *progfuncs, union eval_s *eval, int type, const char *s); void (PDECL *SetStringField) (pubprogfuncs_t *progfuncs, struct edict_s *ed, string_t *fld, const char *str, pbool str_is_static); //if ed is null, fld points to a global. if str_is_static, then s doesn't need its own memory allocated. + pbool (PDECL *DumpProfile) (pubprogfuncs_t *progfuncs); }; typedef struct progexterns_s { @@ -240,7 +241,7 @@ typedef union eval_s #ifndef DLL_PROG -#define PR_Configure(pf, memsize, max_progs) (*pf->Configure) (pf, memsize, max_progs) +#define PR_Configure(pf, memsize, max_progs, profiling) (*pf->Configure) (pf, memsize, max_progs, profiling) #define PR_LoadProgs(pf, s, headercrc, builtins, numb) (*pf->LoadProgs) (pf, s, headercrc, builtins, numb) #define PR_InitEnts(pf, maxents) (*pf->InitEnts) (pf, maxents) #define PR_ExecuteProgram(pf, fnum) (*pf->ExecuteProgram) (pf, fnum) diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 08e31cdd..c6c54b04 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -350,7 +350,7 @@ typedef struct QCC_def_s struct QCC_def_s *scope; // function the var was defined in, or NULL struct QCC_def_s *deftail; // arrays and structs create multiple globaldef objects providing different types at the different parts of the single object (struct), or alternative names (vectors). this allows us to correctly set the const type based upon how its initialised. struct QCC_def_s *generatedfor; - int initialized; // 1 when a declaration included "= immediate" + int initialized; // 1 when a declaration included "= immediate". 2 = extern. 3 = don't warn (unless actually called) int constant; // 1 says we can use the value over and over again int references; diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 2a726ec4..521c8c80 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -4228,9 +4228,10 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou if (!QCC_PR_CheckToken(")")) { - rettype = QCC_TypeForName(QCC_PR_ParseName()); + char *nam = QCC_PR_ParseName(); + rettype = QCC_TypeForName(nam); if (!rettype || rettype->type != ev_entity) - QCC_PR_ParseError(ERR_NOTANAME, "Spawn operator with undefined class"); + QCC_PR_ParseError(ERR_NOTANAME, "Spawn operator with undefined class: %s", nam); } else rettype = NULL; //default, corrected to entity later @@ -5542,22 +5543,17 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo if (assumeclass && assumeclass->parentclass) { //try getting a member. QCC_type_t *type; - type = assumeclass; - while(type) + for(type = assumeclass; type && !d; type = type->parentclass) { //look for virtual things sprintf(membername, "%s::"MEMBERFIELDNAME, type->name, name); d = QCC_PR_GetDef (NULL, membername, pr_scope, false, 0, false); - if (d) - break; - + } + for(type = assumeclass; type && !d; type = type->parentclass) + { //look for non-virtual things (functions: after virtual stuff, because this will find the actual function def too) sprintf(membername, "%s::%s", type->name, name); d = QCC_PR_GetDef (NULL, membername, pr_scope, false, 0, false); - if (d) - break; - - type = type->parentclass; } } if (!d) @@ -6516,7 +6512,7 @@ QCC_def_t *QCC_StoreToRef(QCC_ref_t *dest, QCC_def_t *source, pbool readable, pb if (dest->type == REF_FIELD) QCC_PR_ParseWarning(WARN_STRICTTYPEMISMATCH, "type mismatch: %s to %s %s.%s", typea, typeb, dest->base->type->name, dest->index->name); else if (dest->index) - QCC_PR_ParseWarning(WARN_STRICTTYPEMISMATCH, "type mismatch: %s to %s[]", typea, typeb, dest->base->name); + QCC_PR_ParseWarning(WARN_STRICTTYPEMISMATCH, "type mismatch: %s to %s[%s]", typea, typeb, dest->base->name, dest->index->name); else QCC_PR_ParseWarning(WARN_STRICTTYPEMISMATCH, "type mismatch: %s to %s %s", typea, typeb, dest->base->name); } @@ -7002,6 +6998,12 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) { QCC_PR_ParseError(0, "Type mismatch on assignment. %s %s %s is not supported\n", lhsr->cast->name, opname, rhsd->type->name); } + else if(lhsr->cast->type == ev_float) + rhsd = QCC_MakeFloatConst(0); + else if(lhsr->cast->type == ev_integer) + rhsd = QCC_MakeIntConst(0); + else + rhsd = QCC_MakeIntConst(0); } else rhsd = QCC_SupplyConversionForAssignment(lhsr->base, rhsd, lhsr->cast->type, true); @@ -7058,11 +7060,10 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) { QCC_PR_DiscardRef(lhsr); if (!qcc_usefulstatement) - QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "Effectless statement"); + QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "Statement does not do anything"); qcc_usefulstatement = false; lhsr = QCC_PR_RefExpression(retbuf, TOP_PRIORITY, exprflags); } - return lhsr; } @@ -7087,7 +7088,7 @@ void QCC_PR_DiscardExpression (int priority, int exprflags) { // int osl = pr_source_line; // pr_source_line = statementstart; - QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "Effectless statement"); + QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "Statement does not do anything"); // pr_source_line = osl; } qcc_usefulstatement = olduseful; @@ -7291,7 +7292,7 @@ void QCC_PR_ParseStatement (void) if (QCC_PR_CheckToken (";")) { if (pr_scope->type->aux_type->type != ev_void) - QCC_PR_ParseWarning(WARN_MISSINGRETURNVALUE, "\'%s\' should return %s", pr_scope->name, pr_scope->type->aux_type->name); + QCC_PR_ParseWarning(WARN_MISSINGRETURNVALUE, "\'%s\' returned nothing, expected %s", pr_scope->name, pr_scope->type->aux_type->name); if (opt_return_only) QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_DONE], 0, 0, NULL)); else @@ -9831,9 +9832,6 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a QCC_def_t *def, *first=NULL; char typebuf[1024]; - if (name && !strcmp(name, "ImpulseCommands")) - QCC_PR_Note(0, strings+s_file, pr_source_line, "Defining %s", name); - #define KEYWORD(x) if (!STRCMP(name, #x) && keyword_##x) {if (keyword_##x)QCC_PR_ParseWarning(WARN_KEYWORDDISABLED, "\""#x"\" keyword used as variable name%s", keywords_coexist?" - coexisting":" - disabling");keyword_##x=keywords_coexist;} if (name) { @@ -10326,11 +10324,15 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type QCC_PR_Expect("{"); for (i = 0; i < arraysize; i++) { + if (QCC_PR_CheckToken("}")) + break; QCC_PR_ParseInitializerType(0, def, type, offset + i*type->size); if (!QCC_PR_CheckToken(",")) + { + QCC_PR_Expect("}"); break; + } } - QCC_PR_Expect("}"); } else { @@ -10441,11 +10443,15 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type isunion = ((type)->type == ev_union); for (partnum = 0; partnum < (type)->num_parms; partnum++) { + if (QCC_PR_CheckToken("}")) + break; QCC_PR_ParseInitializerType((type)->params[partnum].arraysize, def, (type)->params[partnum].type, offset + (type)->params[partnum].ofs); if (isunion || !QCC_PR_CheckToken(",")) + { + QCC_PR_Expect("}"); break; + } } - QCC_PR_Expect("}"); return; } else @@ -11215,7 +11221,7 @@ void QCC_PR_ParseDefs (char *classname) gd_flags = 0; if (isstatic) gd_flags |= GDF_STATIC; - if (isconstant) + if (isconstant || (type->type == ev_function && !isvar)) gd_flags |= GDF_CONST; if (!nosave) gd_flags |= GDF_SAVED; @@ -11341,11 +11347,8 @@ void QCC_PR_ParseDefs (char *classname) } else { - if (type->type == ev_function && isvar) - { + if (type->type == ev_function) isconstant = !isvar; - def->initialized = 1; - } if (type->type == ev_field) { diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 0a4f5631..9cae4366 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -647,7 +647,7 @@ pbool QCC_PR_Precompiler(void) QCC_PR_SkipToEndOfLine(false); - QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s", msg); + QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s\n", msg); } else if (!strncmp(directive, "warning", 7)) { @@ -659,7 +659,7 @@ pbool QCC_PR_Precompiler(void) QCC_PR_SkipToEndOfLine(false); - QCC_PR_ParseWarning(WARN_PRECOMPILERMESSAGE, "#warning: %s", msg); + QCC_PR_ParseWarning(WARN_PRECOMPILERMESSAGE, "#warning: %s\n", msg); } else if (!strncmp(directive, "message", 7)) { @@ -4200,6 +4200,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) while (!QCC_PR_CheckToken("}")) { pbool havebody = false; + pbool isnull = false; pbool isvirt = false; pbool isnonvirt = false; pbool isstatic = false; @@ -4279,70 +4280,80 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) if (pr_scope) QCC_Error(ERR_INTERNAL, "Nested function declaration"); + isnull = (QCC_PR_CheckImmediate("0") || QCC_PR_CheckImmediate("0i")); sprintf(membername, "%s::%s", classname, parmname); - def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, GDF_CONST); - - if (newparm->type != ev_function) - QCC_Error(ERR_INTERNAL, "Can only initialise member functions"); + if (isnull) + { + def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, 0); + G_FUNCTION(def->ofs) = 0; + def->initialized = 1; + } else { - extern unsigned int locals_end, locals_start; - extern QCC_type_t *pr_classtype; - QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type); + def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, GDF_CONST); - if (autoprototype) - { - QCC_PR_Expect("{"); - - { - int blev = 1; - //balance out the { and } - while(blev) - { - if (pr_token_type == tt_eof) - break; - if (QCC_PR_CheckToken("{")) - blev++; - else if (QCC_PR_CheckToken("}")) - blev--; - else - QCC_PR_Lex(); //ignore it. - } - } - } + if (newparm->type != ev_function) + QCC_Error(ERR_INTERNAL, "Can only initialise member functions"); else { - pr_scope = def; - pr_classtype = newt; - f = QCC_PR_ParseImmediateStatements (newparm); - pr_classtype = NULL; - pr_scope = NULL; - G_FUNCTION(def->ofs) = numfunctions; - f->def = def; - def->initialized = 1; + extern unsigned int locals_end, locals_start; + extern QCC_type_t *pr_classtype; + QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type); - if (numfunctions >= MAX_FUNCTIONS) - QCC_Error(ERR_INTERNAL, "Too many function defs"); - - // fill in the dfunction - df = &functions[numfunctions]; - numfunctions++; - if (f->builtin) - df->first_statement = -f->builtin; - else - df->first_statement = f->code; - - if (f->builtin && opt_function_names) - optres_function_names += strlen(f->def->name); - else - df->s_name = QCC_CopyString (f->def->name); - df->s_file = s_file; - df->numparms = f->def->type->num_parms; - df->locals = locals_end - locals_start; - df->parm_start = locals_start; - for (i=0 ; inumparms ; i++) + if (autoprototype) { - df->parm_size[i] = newparm->params[i].type->size; + QCC_PR_Expect("{"); + + { + int blev = 1; + //balance out the { and } + while(blev) + { + if (pr_token_type == tt_eof) + break; + if (QCC_PR_CheckToken("{")) + blev++; + else if (QCC_PR_CheckToken("}")) + blev--; + else + QCC_PR_Lex(); //ignore it. + } + } + } + else + { + pr_scope = def; + pr_classtype = newt; + f = QCC_PR_ParseImmediateStatements (newparm); + pr_classtype = NULL; + pr_scope = NULL; + G_FUNCTION(def->ofs) = numfunctions; + f->def = def; + def->initialized = 1; + + if (numfunctions >= MAX_FUNCTIONS) + QCC_Error(ERR_INTERNAL, "Too many function defs"); + + // fill in the dfunction + df = &functions[numfunctions]; + numfunctions++; + if (f->builtin) + df->first_statement = -f->builtin; + else + df->first_statement = f->code; + + if (f->builtin && opt_function_names) + optres_function_names += strlen(f->def->name); + else + df->s_name = QCC_CopyString (f->def->name); + df->s_file = s_file; + df->numparms = f->def->type->num_parms; + df->locals = locals_end - locals_start; + df->parm_start = locals_start; + for (i=0 ; inumparms ; i++) + { + df->parm_size[i] = newparm->params[i].type->size; + } } } } @@ -4471,7 +4482,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) //actually, that seems pointless. sprintf(membername, "%s::"MEMBERFIELDNAME, classname, parmname); // printf("define %s -> %s\n", membername, d->name); - d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, 0, d->ofs, true, GDF_CONST|GDF_STRIP); + d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, 0, d->ofs, true, (isnull?0:GDF_CONST)|GDF_STRIP); d->references++; //always referenced, so you can inherit safely. } diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 720736f4..e6b0ab44 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -1075,7 +1075,7 @@ strofs = (strofs+3)&~3; } } - if (debugtarget || opt_filenames) + if (!opt_filenames) { statement_linenums = qccHunkAlloc(sizeof(statement_linenums) * numstatements); for (i = 0; i < numstatements; i++) @@ -1416,7 +1416,7 @@ strofs = (strofs+3)&~3; progs.ofsbodylessfuncs = SafeSeek (h, 0, SEEK_CUR); progs.numbodylessfuncs = WriteBodylessFuncs(h); - if (debugtarget) + if (debugtarget && statement_linenums) { progs.ofslinenums = SafeSeek (h, 0, SEEK_CUR); if (progs.blockscompressed&64) @@ -1431,6 +1431,7 @@ strofs = (strofs+3)&~3; } else SafeWrite (h, statement_linenums, numstatements*sizeof(int)); + statement_linenums = NULL; } else progs.ofslinenums = 0; @@ -3332,9 +3333,11 @@ memset(pr_immediate_string, 0, sizeof(pr_immediate_string)); sprintf (qccmprogsdat, "%s", argv[p+1]); else { //look for a preprogs.src... :o) - sprintf (qccmprogsdat, "preprogs.src"); + sprintf (qccmprogsdat, "%spreprogs.src", qccmsourcedir); if (externs->FileSize(qccmprogsdat) <= 0) sprintf (qccmprogsdat, "progs.src"); + else + sprintf (qccmprogsdat, "preprogs.src"); } numsourcefiles = 0; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index f3332577..fc8ea6e8 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -61,7 +61,6 @@ cvar_t noexit = CVAR("noexit", "0"); cvar_t pr_ssqc_memsize = CVARD("pr_ssqc_memsize", "-1", "The ammount of memory available to the QC vm. This has a theoretical maximum of 1gb, but that value can only really be used in 64bit builds. -1 will attempt to use some conservative default, but you may need to increase it. Consider also clearing pr_fixbrokenqccarrays if you need to change this cvar."); /*cvars purely for compat with others*/ -cvar_t dpcompat_trailparticles = CVARD("dpcompat_trailparticles", "0", "Swaps the parameter order of the trailparticles builtin so that mods that target DP only can still run."); cvar_t pr_imitatemvdsv = CVARFD("pr_imitatemvdsv", "0", CVAR_LATCH, "Enables mvdsv-specific builtins, and fakes identifiers so that mods made for mvdsv can run properly and with the full feature set."); /*compat with frikqcc's arrays (ensures that unknown fields are at the same offsets*/ @@ -1054,7 +1053,7 @@ void PR_Decompile_f(void) if (!svprogfuncs) { Q_SetProgsParms(false); - PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS); + PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS, 0); } @@ -1126,7 +1125,7 @@ void PR_ApplyCompilation_f (void) s = PR_SaveEnts(svprogfuncs, NULL, &len, 0, 1); - PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS); + PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS, pr_enable_profiling.ival); PR_RegisterFields(); PR_InitEnts(svprogfuncs, sv.world.max_edicts); @@ -1222,6 +1221,23 @@ void PR_WatchPoint_f(void) Cvar_Set(Cvar_FindVar("debugger"), "1"); } +static void PR_SSProfile_f(void) +{ + if (svprogfuncs && svprogfuncs->DumpProfile) + if (!svprogfuncs->DumpProfile(svprogfuncs)) + Con_Printf("Please set pr_enable_profiling and restart the map first\n"); +} + +static void PR_SSPoke_f(void) +{ + if (!SV_MayCheat()) + Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n"); + else if (svprogfuncs && svprogfuncs->EvaluateDebugString) + Con_TPrintf("Result: %s\n", svprogfuncs->EvaluateDebugString(svprogfuncs, Cmd_Args())); + else + Con_TPrintf ("not supported.\n"); +} + void PR_SSCoreDump_f(void) { if (!svprogfuncs) @@ -1267,6 +1283,8 @@ void PR_Init(void) Cmd_AddCommand ("compile", PR_Compile_f); Cmd_AddCommand ("applycompile", PR_ApplyCompilation_f); Cmd_AddCommand ("coredump_ssqc", PR_SSCoreDump_f); + Cmd_AddCommand ("poke_ssqc", PR_SSPoke_f); + Cmd_AddCommand ("profile_ssqc", PR_SSProfile_f); Cmd_AddCommand ("extensionlist_ssqc", PR_SVExtensionList_f); Cmd_AddCommand ("pr_dumpplatform", PR_DumpPlatform_f); @@ -1276,7 +1294,6 @@ void PR_Init(void) Cmd_AddCommand ("svtestprogs", QCLibTest); #endif */ - Cvar_Register(&dpcompat_trailparticles, "Darkplaces compatibility"); Cvar_Register(&pr_imitatemvdsv, cvargroup_progs); Cvar_Register(&pr_fixbrokenqccarrays, cvargroup_progs); @@ -1353,7 +1370,7 @@ void Q_InitProgs(void) // load progs to get entity field count - PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS); + PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS, pr_enable_profiling.ival); PR_RegisterFields(); @@ -5129,26 +5146,40 @@ void QCBUILTIN PF_logfrag (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa edict_t *ent1, *ent2; int e1, e2; char *s; + sizebuf_t *sz; ent1 = G_EDICT(prinst, OFS_PARM0); ent2 = G_EDICT(prinst, OFS_PARM1); - e1 = NUM_FOR_EDICT(prinst, ent1); - e2 = NUM_FOR_EDICT(prinst, ent2); + e1 = NUM_FOR_EDICT(prinst, ent1)-1; + e2 = NUM_FOR_EDICT(prinst, ent2)-1; - if (e1 < 1 || e1 > sv.allocated_client_slots - || e2 < 1 || e2 > sv.allocated_client_slots) + if (e1 < 0 || e1 >= sv.allocated_client_slots + || e2 < 0 || e2 >= sv.allocated_client_slots) return; #ifdef SVRANKING if (e1 != e2) //don't get a point for suicide. - svs.clients[e1-1].kills += 1; - svs.clients[e2-1].deaths += 1; + svs.clients[e1].kills += 1; + svs.clients[e2].deaths += 1; #endif - s = va("\\%s\\%s\\\n",svs.clients[e1-1].name, svs.clients[e2-1].name); + s = va("\\%s\\%s\\\n",svs.clients[e1].name, svs.clients[e2].name); - SZ_Print (&svs.log[svs.logsequence&1], s); + //print it to the fraglog buffer for masters/etc to query + sz = &svs.log[svs.logsequence&(FRAGLOG_BUFFERS-1)]; + if (sz->cursize && sz->cursize+strlen(s)+1 >= sz->maxsize) + { + // swap buffers and bump sequence + svs.logtime = realtime; + svs.logsequence++; + sz = &svs.log[svs.logsequence&(FRAGLOG_BUFFERS-1)]; + sz->cursize = 0; + Con_TPrintf ("beginning fraglog sequence %i\n", svs.logsequence); + } + SZ_Print (sz, s); + + //print it to our local fraglog file. if (sv_fraglogfile) { VFS_WRITE(sv_fraglogfile, s, strlen(s)); @@ -7612,7 +7643,7 @@ static void QCBUILTIN PF_sv_trailparticles(pubprogfuncs_t *prinst, struct global float *end = G_VECTOR(OFS_PARM3); /*DP gets this wrong*/ - if (dpcompat_trailparticles.ival) + if (G_INT(OFS_PARM1) >= MAX_EDICTS) { ednum = G_EDICTNUM(prinst, OFS_PARM0); efnum = G_FLOAT(OFS_PARM1); @@ -9177,7 +9208,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs //DP_QC_FINDFLOAT {"findfloat", PF_FindFloat, 0, 0, 0, 98, D("entity(entity start, .float fld, float match)", "Equivelent to the find builtin, but instead of comparing strings, this builtin compares floats. This builtin requires multiple calls in order to scan all entities - set start to the previous call's return value.\nworld is returned when there are no more entities.")}, // #98 (DP_QC_FINDFLOAT) - {"checkextension", PF_checkextension, 99, 99, 0, 99, D("float(string extname)", "Checks for an extension by its name (eg: checkextension(\"FRIK_FILE\") says that its okay to go ahead and use strcat).\nUse cvar_value(\"pr_checkextension\") to see if this builtin exists.")}, // #99 //darkplaces system - query a string to see if the mod supports X Y and Z. + {"checkextension", PF_checkextension, 99, 99, 0, 99, D("float(string extname)", "Checks for an extension by its name (eg: checkextension(\"FRIK_FILE\") says that its okay to go ahead and use strcat).\nUse cvar(\"pr_checkextension\") to see if this builtin exists.")}, // #99 //darkplaces system - query a string to see if the mod supports X Y and Z. {"builtin_find", PF_builtinsupported,100, 100, 0, 100, D("float(string builtinname)", "Looks to see if the named builtin is valid, and returns the builtin number it exists at.")}, // #100 //per builtin system. {"anglemod", PF_anglemod, 0, 0, 0, 102, "float(float value)"}, {"qsg_cvar_string", PF_cvar_string, 0, 0, 0, 103, D("string(string cvarname)","An old/legacy equivelent of more recent/common builtins in order to read a cvar's string value."), true}, @@ -9451,7 +9482,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"memsetval", PF_memsetval, 0, 0, 0, 389, D("void(__variant *dst, float ofs, __variant val)", "Changes the 32bit value stored at the specified pointer-with-offset.")}, {"memptradd", PF_memptradd, 0, 0, 0, 390, D("__variant*(__variant *base, float ofs)", "Perform some pointer maths. Woo.")}, - {"con_getset", PF_Fixme, 0, 0, 0, 391, D("string(string conname, string field, optional string newvalue)", "Reads or sets a property from a console object. The old value is returned. Iterrate through consoles with the 'next' field.")}, + {"con_getset", PF_Fixme, 0, 0, 0, 391, D("string(string conname, string field, optional string newvalue)", "Reads or sets a property from a console object. The old value is returned. Iterrate through consoles with the 'next' field. Valid properties: title, name, next, unseen, markup, forceutf8, close, clear, hidden, linecount")}, {"con_printf", PF_Fixme, 0, 0, 0, 392, D("void(string conname, string messagefmt, ...)", "Prints onto a named console.")}, {"con_draw", PF_Fixme, 0, 0, 0, 393, D("void(string conname, vector pos, vector size, float fontsize)", "Draws the named console.")}, {"con_input", PF_Fixme, 0, 0, 0, 394, D("float(string conname, float inevtype, float parama, float paramb, float paramc)", "Forwards input events to the named console. Mouse updates should be absolute only.")}, @@ -10124,7 +10155,7 @@ void PR_DumpPlatform_f(void) {"ltime", ".float", QW|NQ}, {"entnum", ".float", CS, "The entity number as its known on the server."}, {"drawmask", ".float", CS, "Acts as a filter in the addentities call."}, - {"predraw", ".float()", CS, "Called by addentities after the filter and before the entity is actually drawn. Do your interpolation and animation in here. Return true to inhibit addition of the entity, and false for the entity to be added to the scene."}, + {"predraw", ".float()", CS, "Called by addentities after the filter and before the entity is actually drawn. Do your interpolation and animation in here. Should return one of the PREDRAW_* constants."}, {"lastruntime", ".float", QW}, {"movetype", ".float", QW|NQ|CS}, {"solid", ".float", QW|NQ|CS}, @@ -10497,6 +10528,10 @@ void PR_DumpPlatform_f(void) {"MF_TRACER2", "const float", QW|NQ, NULL, EF_MF_TRACER2>>24}, {"MF_TRACER3", "const float", QW|NQ, NULL, EF_MF_TRACER3>>24}, + {"PFLAGS_NOSHADOW", "const float", QW|NQ|CS, "Associated RT lights attached will not cast shadows, making them significantly faster to draw.", PFLAGS_NOSHADOW}, + {"PFLAGS_CORONA", "const float", QW|NQ|CS, "Enables support of coronas on the associated rtlights.", PFLAGS_CORONA}, + {"PFLAGS_FULLDYNAMIC", "const float", QW|NQ, "When set in self.pflags, enables fully-customised dynamic lights. Custom rtlight information is not otherwise used.", PFLAGS_FULLDYNAMIC}, + //including these for csqc stat types. // {"EV_VOID", "const float", QW|NQ, NULL, ev_void}, {"EV_STRING", "const float", QW|NQ, NULL, ev_string}, @@ -10598,6 +10633,8 @@ void PR_DumpPlatform_f(void) {"MASK_ENGINE", "const float", CS, "Valid as an argument for addentities. If specified, all non-csqc entities will be added to the scene.", MASK_DELTA}, {"MASK_VIEWMODEL", "const float", CS, "Valid as an argument for addentities. If specified, the regular engine viewmodel will be added to the scene.", MASK_STDVIEWMODEL}, + {"PREDRAW_AUTOADD", "const float", CS, "Valid as a return value from the predraw function. Returning this will cause the engine to automatically invoke addentity(self) for you.", false}, + {"PREDRAW_NEXT", "const float", CS, "Valid as a return value from the predraw function. Returning this will simply move on to the next entity without the autoadd behaviour, so can be used for particle/invisible/special entites, or entities that were explicitly drawn with addentity.", true}, {"LFIELD_ORIGIN", "const float", CS, NULL, lfield_origin}, {"LFIELD_COLOUR", "const float", CS, NULL, lfield_colour}, diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 9f414f0e..349b7a4e 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -6,6 +6,7 @@ extern cvar_t skill; extern cvar_t deathmatch; extern cvar_t coop; extern cvar_t teamplay; +extern cvar_t pr_enable_profiling; void SV_Savegame_f (void); @@ -259,7 +260,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version) Q_SetProgsParms(false); svs.numprogs = 0; - PR_Configure(svprogfuncs, -1, MAX_PROGS); + PR_Configure(svprogfuncs, -1, MAX_PROGS, pr_enable_profiling.ival); PR_RegisterFields(); PR_InitEnts(svprogfuncs, sv.world.max_edicts); //just in case the max edicts isn't set. progstype = pt; //presumably the progs.dat will be what they were before. @@ -678,7 +679,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea if (progstype != PROG_H2) { Q_SetProgsParms(false); - PR_Configure(svprogfuncs, -1, MAX_PROGS); + PR_Configure(svprogfuncs, -1, MAX_PROGS, pr_enable_profiling.ival); PR_RegisterFields(); PR_InitEnts(svprogfuncs, sv.world.max_edicts); } diff --git a/engine/server/server.h b/engine/server/server.h index bbb87b19..0664c6d5 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -807,8 +807,10 @@ typedef struct // log messages are used so that fraglog processes can get stats int logsequence; // the message currently being filled double logtime; // time of last swap - sizebuf_t log[2]; - qbyte log_buf[2][MAX_DATAGRAM]; + +#define FRAGLOG_BUFFERS 8 + sizebuf_t log[FRAGLOG_BUFFERS]; + qbyte log_buf[FRAGLOG_BUFFERS][MAX_DATAGRAM]; challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index b9ed5271..28e7a99a 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -256,7 +256,7 @@ static void SV_God_f (void) { if (!SV_MayCheat()) { - Con_TPrintf ("You must run the server with +sv_cheats 1 to enable this command.\n"); + Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n"); return; } @@ -276,7 +276,7 @@ static void SV_Noclip_f (void) { if (!SV_MayCheat()) { - Con_TPrintf ("You must run the server with +sv_cheats 1 to enable this command.\n"); + Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n"); return; } @@ -312,7 +312,7 @@ static void SV_Give_f (void) if (!SV_MayCheat()) { - Con_TPrintf ("You must run the server with +sv_cheats 1 to enable this command.\n"); + Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n"); return; } diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 9625579c..3145fc85 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -2584,15 +2584,11 @@ int glowsize=0, glowcolor=0, colourmod=0; // // write the message // -#ifdef PARANOID - MSG_WriteByte (msg,(bits | NQU_SIGNAL) & 0xFF); //gets caught on 'range error' -#else - MSG_WriteByte (msg,bits | NQU_SIGNAL); -#endif + MSG_WriteByte (msg,(bits | NQU_SIGNAL) & 0xff); //gets caught on 'range error' - if (bits & NQU_MOREBITS) MSG_WriteByte (msg, bits>>8); - if (bits & DPU_EXTEND1) MSG_WriteByte (msg, bits>>16); - if (bits & DPU_EXTEND2) MSG_WriteByte (msg, bits>>24); + if (bits & NQU_MOREBITS) MSG_WriteByte (msg, (bits>>8)&0xff); + if (bits & DPU_EXTEND1) MSG_WriteByte (msg, (bits>>16)&0xff); + if (bits & DPU_EXTEND2) MSG_WriteByte (msg, (bits>>24)&0xff); if (bits & NQU_LONGENTITY) MSG_WriteShort (msg,ent->number); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index deebf251..708fd976 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -92,7 +92,7 @@ cvar_t sv_limittics = CVARD("sv_limittics","3", "The maximum number of ticks tha cvar_t sv_nailhack = CVARD("sv_nailhack","0", "If set to 1, disables the nail entity networking optimisation. This hack was popularised by qizmo which recommends it for better compression. Also allows clients to interplate nail positions and add trails."); cvar_t sv_nopvs = CVARD("sv_nopvs", "0", "Set to 1 to ignore pvs on the server. This can make wallhacks more dangerous, so should only be used for debugging."); - +cvar_t fraglog_public = CVARD("fraglog_public", "1", "Enables support for connectionless fraglog requests"); cvar_t timeout = SCVAR("timeout","65"); // seconds without any message cvar_t zombietime = SCVAR("zombietime", "2"); // seconds to sink messages @@ -1258,23 +1258,22 @@ SV_CheckLog =================== */ -#define LOG_HIGHWATER 4096 #define LOG_FLUSH 10*60 void SV_CheckLog (void) { sizebuf_t *sz; - sz = &svs.log[svs.logsequence&1]; + sz = &svs.log[svs.logsequence&(FRAGLOG_BUFFERS-1)]; - // bump sequence if allmost full, or ten minutes have passed and + // bump sequence ten minutes have passed and // there is something still sitting there - if (sz->cursize > LOG_HIGHWATER - || (realtime - svs.logtime > LOG_FLUSH && sz->cursize) ) + //logfrag does the rotation for a full log. + if (realtime - svs.logtime > LOG_FLUSH && sz->cursize) { // swap buffers and bump sequence svs.logtime = realtime; svs.logsequence++; - sz = &svs.log[svs.logsequence&1]; + sz = &svs.log[svs.logsequence&(FRAGLOG_BUFFERS-1)]; sz->cursize = 0; Con_TPrintf ("beginning fraglog sequence %i\n", svs.logsequence); } @@ -1293,27 +1292,41 @@ instead of the data. */ void SVC_Log (void) { - int seq; + unsigned int seq; char data[MAX_DATAGRAM+64]; char adr[MAX_ADR_SIZE]; if (Cmd_Argc() == 2) - seq = atoi(Cmd_Argv(1)); - else - seq = -1; + { + seq = strtoul(Cmd_Argv(1), NULL, 0); + //seq is the last one that the client already has - if (seq == svs.logsequence-1 || !sv_fraglogfile) - { // they already have this data, or we aren't logging frags + if (seq < svs.logsequence-(FRAGLOG_BUFFERS-1)) + seq = svs.logsequence-(FRAGLOG_BUFFERS-1); //send them this sequence + else if (seq == svs.logsequence) + { //current log isn't available as its not complete yet. + data[0] = A2A_NACK; + NET_SendPacket (NS_SERVER, 1, data, &net_from); + return; + } + else if (seq > svs.logsequence) //future logs are not valid either. reply with the last that was. this is for compat, just in case. + seq = svs.logsequence-1; + else + seq = seq+1; //they will get the next sequence from the one they already have + } + else + seq = 0; + + if (!fraglog_public.ival) + { //frag logs are not public (for DoS protection perhaps?. data[0] = A2A_NACK; NET_SendPacket (NS_SERVER, 1, data, &net_from); return; } - Con_DPrintf ("sending log %i to %s\n", svs.logsequence-1, NET_AdrToString(adr, sizeof(adr), &net_from)); - - sprintf (data, "stdlog %i\n", svs.logsequence-1); - strcat (data, (char *)svs.log_buf[((svs.logsequence-1)&1)]); + Con_DPrintf ("sending log %i to %s\n", seq, NET_AdrToString(adr, sizeof(adr), &net_from)); + Q_snprintfz(data, sizeof(data), "stdlog %i\n%s", seq, (char *)svs.log_buf[seq&(FRAGLOG_BUFFERS-1)]); NET_SendPacket (NS_SERVER, strlen(data)+1, data, &net_from); } @@ -5192,6 +5205,7 @@ void SV_InitLocal (void) Cvar_Register (&sv_listen_dp, cvargroup_servercontrol); Cvar_Register (&sv_listen_q3, cvargroup_servercontrol); sv_listen_qw.restriction = RESTRICT_MAX; + Cvar_Register (&fraglog_public, cvargroup_servercontrol); SVNET_RegisterCvars(); diff --git a/plugins/Makefile b/plugins/Makefile index 4e81dcf0..5781c67a 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -108,6 +108,8 @@ avplug/libavformat/avformat.h: distclean: rm avplug/libavformat/avformat.h +-include Makefile.private + $(OUT_DIR)/fteplug_avplug$(PLUG_NATIVE_EXT): avplug/avencode.c avplug/avdecode.c plugin.c qvm_api.c $(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -s -o $(OUT_DIR)/fteplug_avplug$(PLUG_NATIVE_EXT) -shared $(PLUG_CFLAGS) -Iavplug/msvc_lib $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS) -lavcodec -lavformat -lavutil -lswscale #native: $(OUT_DIR)/fteplug_avplug$(PLUG_NATIVE_EXT) diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index 764fca9d..95ee046b 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -2881,6 +2881,24 @@ void JCL_ParseMessage(jclient_t *jcl, xmltree_t *tree) } } + if (!strcmp(type, "error")) + { + ot = XML_ChildOfTree(tree, "body", 0); + if (ot) + { + unparsable = false; + if (f) + { + if (!strncmp(ot->body, "/me ", 4)) + Con_SubPrintf(ctx, "* ^2%s^7%s\n", f, ot->body+3); + else + Con_SubPrintf(ctx, "^2%s^7: %s\n", f, ot->body); + } + } + else + Con_SubPrintf(ctx, "error sending message: %s\r", f); + } + if (f) { ot = XML_ChildOfTree(tree, "composing", 0);