qc: qc temp-strings are now garbage collected. this makes strzone redundant.

net: revert the player angles inversion thing from last build. hack some angles. gonna need to tweak the protocol.
net: cl_lerp_players is smoother, and defaulted. lets see how many people complain.
cl: fix juddering with chase_active+prediction.
cl: download progress where the total size is not known now displays something more sane.
cl: fixed some issues with rawinput keyboards.
cl: added autoupdate option to the menu.
cl: autoupdate defaults to a new 'tested' set of builds, instead of the completely untested svn builds. 
cl: added 'borderless windowed' option to the  menus. works on windows.
cl: saved games save a preview screenshot.
cl: fix some memory leaks on shutdown.
cl: added 'setrenderer random' option, might be useful for modders in that it helps highlight bugs/differences between renderers...
qc: r_showbboxes now displays the fields of the various entities.
tweaked entity lighting to overbright more gracefully.
gl: fixed crepuscular lighting.
qcc: added % operator.
qcc: added inline keyword.
qcc: some fixes for accessors.
qccgui: now prompts for exe+basedir.
sv: added sv_specprint, ala mvdsv.
sv: stats now sent over the unreliable channel instead of the reliable one. this allows them to change more frequently.
sv: rewrote speedcheat detection. clients will be throttled instead of kicked. unresponsive clients will be simulated instead of freezing in mid-air.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4829 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-01-21 18:18:37 +00:00
parent f81ecbd44c
commit 2ea981fe90
71 changed files with 2380 additions and 563 deletions

View File

@ -894,10 +894,11 @@ void CLFTE_ParseEntities(void)
if (cl.do_lerp_players)
{
float packetage = (realtime - cl.outframes[cl.ackedmovesequence & UPDATE_MASK].senttime) - cls.latency;
//predict in-place based upon calculated latencies and stuff, stuff can then be interpolated properly
for (oldindex = 0; oldindex < newp->num_entities; oldindex++)
{
CL_PredictEntityMovement(newp->entities + oldindex, (cl.inframes[cl.parsecount&UPDATE_MASK].packet_entities.servertime - cl.currentpacktime) + (realtime - cl.gametimemark));
CL_PredictEntityMovement(newp->entities + oldindex, (newp->entities[oldindex].u.q1.msec / 1000.0f + packetage) *0.5);
}
}
@ -2972,6 +2973,8 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp
continue;
}
//FIXME: find a packet where this entity changed.
snew__origin = snew->u.q1.predorg;
sold__origin = sold->u.q1.predorg;
}
@ -3524,16 +3527,7 @@ void CL_LinkPacketEntities (void)
}
}
if (state->u.q1.pmovetype)
{
vec3_t vel;
VectorScale(state->u.q1.velocity, (1/8.0), vel);
//players get special logic, as the angles on the wire are their raw view angles
//FIXME: EGADS! VILE!
angles[0] *= 1/3.0; //fixme: gravity dir.
angles[2] += V_CalcRoll(angles, vel)*4;
}
else if (model && model->type == mod_alias)
if (model && model->type == mod_alias)
angles[0]*=-1; //carmack screwed up when he added alias models - they pitch the wrong way.
VectorCopy(angles, ent->angles);
AngleVectors(angles, ent->axis[0], ent->axis[1], ent->axis[2]);

View File

@ -77,7 +77,7 @@ cvar_t m_yaw = CVARF("m_yaw","0.022", CVAR_ARCHIVE);
cvar_t m_forward = CVARF("m_forward","1", CVAR_ARCHIVE);
cvar_t m_side = CVARF("m_side","0.8", CVAR_ARCHIVE);
cvar_t cl_lerp_players = CVARD("cl_lerp_players", "0", "Set this to make other players smoother, though it may increase effective latency. Affects only QuakeWorld.");
cvar_t cl_lerp_players = CVARD("cl_lerp_players", "1", "Set this to make other players smoother, though it may increase effective latency. Affects only QuakeWorld.");
cvar_t cl_predict_players = CVARD("cl_predict_players", "1", "Clear this cvar to see ents exactly how they are on the server.");
cvar_t cl_predict_players_frac = CVARD("cl_predict_players_frac", "0.9", "How much of other players to predict. Values less than 1 will help minimize overruns.");
cvar_t cl_solid_players = CVARD("cl_solid_players", "1", "Consider other players as solid for player prediction.");

View File

@ -754,14 +754,22 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st
else
VectorScale(state->u.q1.velocity, 1/8.0, plstate->velocity);
VectorCopy(state->angles, plstate->viewangles);
plstate->viewangles[0] *= -3;
if (state->u.q1.pmovetype)
plstate->viewangles[0] *= -3;
plstate->viewangles[2] = V_CalcRoll(plstate->viewangles, plstate->velocity);
a[0] = ((-192-state->u.q1.gravitydir[0])/256.0f) * 360;
a[1] = (state->u.q1.gravitydir[1]/256.0f) * 360;
a[2] = 0;
AngleVectors(a, plstate->gravitydir, NULL, NULL);
CL_DecodeStateSize(state->solid, state->modelindex, plstate->szmins, plstate->szmaxs);
if (!state->solid)
{
VectorSet(plstate->szmins, -16, -16, -24);
VectorSet(plstate->szmaxs, 16, 16, 32);
}
else
CL_DecodeStateSize(state->solid, state->modelindex, plstate->szmins, plstate->szmaxs);
}
static void CL_EntStateToPlayerCommand(usercmd_t *cmd, entity_state_t *state, float age)
{
@ -792,9 +800,10 @@ void CL_PredictEntityMovement(entity_state_t *estate, float age)
player_state_t startstate, resultstate;
usercmd_t cmd;
int oldphysent;
extern cvar_t cl_predict_players;
//build the entitystate state into a player state for prediction to use
if (!estate->u.q1.pmovetype)
if (!estate->u.q1.pmovetype || !cl_predict_players.ival || age <= 0)
VectorCopy(estate->origin, estate->u.q1.predorg);
else
{
@ -1070,8 +1079,11 @@ void CL_PredictMovePNum (int seat)
if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
//putting weapon frames in there was probably a stupid idea.
pv->stats[STAT_WEAPONFRAME] = cl.players[pv->playernum].stats[STAT_WEAPONFRAME] = pe->entities[i].u.q1.weaponframe;
pv->statsf[STAT_WEAPONFRAME] = cl.players[pv->playernum].statsf[STAT_WEAPONFRAME] = pe->entities[i].u.q1.weaponframe;
if (!(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{
pv->stats[STAT_WEAPONFRAME] = cl.players[pv->playernum].stats[STAT_WEAPONFRAME] = pe->entities[i].u.q1.weaponframe;
pv->statsf[STAT_WEAPONFRAME] = cl.players[pv->playernum].statsf[STAT_WEAPONFRAME] = pe->entities[i].u.q1.weaponframe;
}
pv->pmovetype = tostate->pm_type;
}
break;
@ -1108,8 +1120,13 @@ void CL_PredictMovePNum (int seat)
//we must always predict a frame, just to ensure that the playerstate's jump status etc is valid for the next frame, even if we're not going to use it for interpolation.
//this assumes that we always have at least one video frame to each network frame, of course.
//note that q2 updates its values via networking rather than propagation.
player_state_t tmp, *next;
// Con_DPrintf(" propagate %i: %f-%f\n", cl.ackedmovesequence+i, fromtime, totime);
CL_PredictUsercmd (seat, pv->viewentity, tostate, &cl.inframes[(toframe+i) & UPDATE_MASK].playerstate[pv->playernum], &of->cmd[seat]);
CL_PredictUsercmd (seat, pv->viewentity, tostate, &tmp, &of->cmd[seat]);
next = &cl.inframes[(toframe+i) & UPDATE_MASK].playerstate[pv->playernum];
next->jump_held = tmp.jump_held;
next->jump_msec = tmp.jump_msec;
VectorCopy(tmp.gravitydir, next->gravitydir);
}
break;
}
@ -1217,23 +1234,23 @@ void CL_PredictMovePNum (int seat)
else
CL_CatagorizePosition(pv, tostate->origin);
if (le)
{
//keep the entity tracking the prediction position, so mirrors don't go all weird
VectorCopy(tostate->origin, le->origin);
if (pv->stats[STAT_HEALTH] > 0)
{
VectorScale(pv->simangles, 1, le->angles);
le->angles[0] *= -0.333;
}
}
// if (cls.demoplayback)
// CL_LerpMove (seat, totime);
CL_CalcCrouch (pv);
pv->waterlevel = pmove.waterlevel;
VectorCopy(pmove.gravitydir, pv->gravitydir);
if (le)
{
//keep the entity tracking the prediction position, so mirrors don't go all weird
VectorMA(pv->simorg, -pv->crouch, pv->gravitydir, le->origin);
if (pv->stats[STAT_HEALTH] > 0)
{
VectorScale(pv->simangles, 1, le->angles);
if (pv->pmovetype == PM_6DOF)
le->angles[0] *= -1;
else
le->angles[0] *= -0.333;
}
}
}
void CL_PredictMove (void)

View File

@ -784,6 +784,12 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
}
c++;
}
if (con->flags & CONF_NOTIMES)
con->current->time = 0;
else
con->current->time = realtime;
}
void Con_Print (char *txt)
@ -1428,13 +1434,28 @@ static int Con_DrawProgress(int left, int right, int y)
progresstext = cls.download->localname;
progresspercent = cls.download->percent;
if (cls.download->sizeunknown && cls.download->size == 0)
progresspercent = -1;
CL_GetDownloadSizes(&count, &total, &extra);
if ((int)(realtime/2)&1 || total == 0)
sprintf(progresspercenttext, " %5.1f%% (%ukbps)", progresspercent, CL_DownloadRate()/1000);
if (progresspercent < 0)
{
if ((int)(realtime/2)&1 || total == 0)
sprintf(progresspercenttext, " (%ukbps)", CL_DownloadRate()/1000);
else
{
sprintf(progresspercenttext, " (%u%skb)", (int)(total/1024), extra?"+":"");
}
}
else
{
sprintf(progresspercenttext, " %5.1f%% (%u%skb)", progresspercent, (int)(total/1024), extra?"+":"");
if ((int)(realtime/2)&1 || total == 0)
sprintf(progresspercenttext, " %5.1f%% (%ukbps)", progresspercent, CL_DownloadRate()/1000);
else
{
sprintf(progresspercenttext, " %5.1f%% (%u%skb)", progresspercent, (int)(total/1024), extra?"+":"");
}
}
}
#ifdef RUNTIMELIGHTING
@ -1529,7 +1550,8 @@ static int Con_DrawProgress(int left, int right, int y)
}
x = Font_DrawChar(x, y, 0xe082|CON_WHITEMASK);
Font_DrawChar(barleft+(barwidth*progresspercent)/100 - Font_CharWidth(0xe083|CON_WHITEMASK)/2, y, 0xe083|CON_WHITEMASK);
if (progresspercent >= 0)
Font_DrawChar(barleft+(barwidth*progresspercent)/100 - Font_CharWidth(0xe083|CON_WHITEMASK)/2, y, 0xe083|CON_WHITEMASK);
y += Font_CharHeight();
}

View File

@ -4142,7 +4142,11 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
tex = Image_FindTexture(identifier, subpath, flags);
if (tex)
{
if (!fallbackdata || tex->status != TEX_FAILED)
//FIXME: race condition is possible here
//if a non-replaced texture is given a fallback while a non-fallback version is still loading, it can still fail.
if (tex->status == TEX_FAILED && fallbackdata)
tex->status = TEX_LOADING;
else if (tex->status != TEX_NOTLOADED)
{
#ifdef LOADERTHREAD
Sys_UnlockMutex(com_resourcemutex);
@ -4185,7 +4189,7 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
b = 4;
break;
default:
Sys_Error("GL_FindTextureFallback: bad format");
Sys_Error("Image_GetTexture: bad format");
}
tex->fallbackdata = BZ_Malloc(fallbackwidth*fallbackheight*b + pb);
memcpy(tex->fallbackdata, fallbackdata, fallbackwidth*fallbackheight*b);
@ -4298,6 +4302,16 @@ void Image_TextureMode_Callback (struct cvar_s *var, char *oldvalue)
if (rf && rf->IMG_UpdateFiltering)
rf->IMG_UpdateFiltering(imagelist, mip, pic, mipcap, anis);
}
qboolean Image_UnloadTexture(image_t *tex)
{
if (tex->status == TEX_LOADED)
{
rf->IMG_DestroyTexture(tex);
tex->status = TEX_NOTLOADED;
return true;
}
return false;
}
//may not create any images yet.
void Image_Init(void)
{

View File

@ -777,7 +777,7 @@ void INS_RawInput_KeyboardDeRegister(void)
// deregister raw input
Rid.usUsagePage = 0x01;
Rid.usUsage = 0x02;
Rid.usUsage = 0x06;
Rid.dwFlags = RIDEV_REMOVE;
Rid.hwndTarget = NULL;
@ -787,17 +787,17 @@ void INS_RawInput_KeyboardDeRegister(void)
void INS_RawInput_DeInit(void)
{
if (rawmicecount > 0)
{
INS_RawInput_MouseDeRegister();
Z_Free(rawmice);
rawmicecount = 0;
}
if (rawkbdcount > 0)
{
INS_RawInput_KeyboardDeRegister();
Z_Free(rawkbd);
rawkbdcount = 0;
}
rawmicecount = 0;
rawkbdcount = 0;
Z_Free(rawmice);
rawmice = NULL;
Z_Free(rawkbd);
rawkbd = NULL;
Z_Free(raw);
raw = NULL;
memset(multicursor_active, 0, sizeof(multicursor_active));
}
#endif
@ -1488,10 +1488,10 @@ void INS_RawInput_KeyboardRead(void)
return;
down = !(raw->data.keyboard.Flags & RI_KEY_BREAK);
wParam = (-down) & 0xC0000000;
lParam = MapVirtualKey(raw->data.keyboard.VKey, 0)<<16;
wParam = raw->data.keyboard.VKey ;//(-down) & 0xC0000000;
lParam = (MapVirtualKey(raw->data.keyboard.VKey, 0)<<16) | ((!!(raw->data.keyboard.Flags & RI_KEY_E0))<<24);
INS_TranslateKeyEvent(wParam, lParam, down, rawkbd[i].qdeviceid);
INS_TranslateKeyEvent(wParam, lParam, down, rawkbd[i].qdeviceid, true);
}
void INS_RawInput_Read(HANDLE in_device_handle)
@ -2103,7 +2103,7 @@ static int MapKey (int vkey)
return key;
}
void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdeviceid)
void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdeviceid, qboolean genkeystate)
{
extern cvar_t in_builtinkeymap;
int qcode;
@ -2118,7 +2118,29 @@ void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdev
{
BYTE keystate[256];
WCHAR wchars[2];
GetKeyboardState(keystate);
if (genkeystate)
{
extern qboolean keydown[K_MAX];
memset(keystate, 0, sizeof(keystate));
//128 for held.
//1 for toggled (ie: caps / num)
keystate[VK_LSHIFT] = 128*!!keydown[K_LSHIFT];
keystate[VK_RSHIFT] = 128*!!keydown[K_RSHIFT];
keystate[VK_LCONTROL] = 128*!!keydown[K_LCTRL];
keystate[VK_RCONTROL] = 128*!!keydown[K_RCTRL];
keystate[VK_LMENU] = 128*!!keydown[K_LALT];
keystate[VK_RMENU] = 128*!!keydown[K_RALT];
//seems to matter
keystate[VK_SHIFT] = keystate[VK_LSHIFT]|keystate[VK_RSHIFT];
keystate[VK_CONTROL] = keystate[VK_LCONTROL]|keystate[VK_RCONTROL];
keystate[VK_MENU] = keystate[VK_LMENU]|keystate[VK_RMENU];
keystate[VK_NUMLOCK] = 1; //doesn't seem to matter?
}
else
GetKeyboardState(keystate);
chars = ToUnicode(wParam, HIWORD(lParam), keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0);
if (chars > 0)

View File

@ -501,7 +501,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
Draw_FunString(xpos+option->common.posx, ypos+option->common.posy, option->text.text);
break;
case mt_button:
Draw_FunStringWidth(xpos + option->common.posx, ypos+option->common.posy, option->button.text, option->common.width, true, !menu->cursoritem && menu->selecteditem == option);
Draw_FunStringWidth(xpos + option->common.posx, ypos+option->common.posy, option->button.text, option->common.width, option->button.rightalign, !menu->cursoritem && menu->selecteditem == option);
break;
#ifdef HEXEN2
case mt_hexen2buttonbigfont:
@ -1306,6 +1306,7 @@ menubutton_t *MC_AddConsoleCommand(menu_t *menu, int lhs, int rhs, int y, const
n->common.posy = y;
n->common.height = 8;
n->common.width = rhs?rhs - lhs:strlen(text)*8;
n->rightalign = true;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
n->command = n->text + strlen(n->text)+1;
@ -1361,6 +1362,7 @@ menubutton_t *MC_AddCommand(menu_t *menu, int lhs, int rhs, int y, char *text, q
n->common.iszone = true;
n->common.posx = lhs;
n->common.posy = y;
n->rightalign = true;
n->text = text;
n->command = NULL;
n->key = command;
@ -1372,7 +1374,7 @@ menubutton_t *MC_AddCommand(menu_t *menu, int lhs, int rhs, int y, char *text, q
return n;
}
menubutton_t *VARGS MC_AddConsoleCommandf(menu_t *menu, int lhs, int rhs, int y, const char *text, char *command, ...)
menubutton_t *VARGS MC_AddConsoleCommandf(menu_t *menu, int lhs, int rhs, int y, qboolean rightalign, const char *text, char *command, ...)
{
va_list argptr;
static char string[1024];
@ -1388,6 +1390,7 @@ menubutton_t *VARGS MC_AddConsoleCommandf(menu_t *menu, int lhs, int rhs, int y,
n->common.posx = lhs;
n->common.posy = y;
n->common.width = rhs-lhs;
n->rightalign = rightalign;
n->text = text;
n->command = (char *)(n+1);
strcpy((char *)(n+1), string);
@ -2350,6 +2353,12 @@ int MC_AddBulk(struct menu_s *menu, menuresel_t *resel, menubulk_t *bulk, int xs
control = (union menuoption_s *)MC_AddCvarCombo(menu, xleft, xtextend, y, bulk->text, bulk->cvar, bulk->options, bulk->values);
break;
case 1: // combo with return value
if (bulk->selectedoption < 0)
{ //invalid...
control = NULL;
spacing = 0;
break;
}
control = (union menuoption_s *)MC_AddCombo(menu, xleft, xtextend, y, bulk->text, bulk->options, bulk->selectedoption);
break;
}

View File

@ -172,12 +172,28 @@ qboolean M_Options_InvertMouse (menucheck_t *option, struct menu_s *menu, chk_se
}
}
void M_Options_Remove(menu_t *m)
{
menucombo_t *c = m->data;
if (c)
Sys_SetAutoUpdateSetting(c->selectedoption);
}
//options menu.
void M_Menu_Options_f (void)
{
extern cvar_t crosshair;
int y;
menuoption_t *updatecbo;
static const char *autoupopts[] = {
"Revert",
"Off",
"Tested(Recommended)",
"Untested(Latest)",
NULL
};
menubulk_t bulk[] = {
MB_CONSOLECMD("Customize controls", "menu_keys\n", "Modify keyboard and mouse inputs."),
MB_CONSOLECMD("Go to console", "toggleconsole\nplay misc/menu2.wav\n", "Open up the engine console."),
@ -192,6 +208,7 @@ void M_Menu_Options_f (void)
MB_CHECKBOXCVAR("Lookspring", lookspring, 0),
MB_CHECKBOXCVAR("Lookstrafe", lookstrafe, 0),
MB_CHECKBOXCVAR("Windowed Mouse", _windowed_mouse, 0),
MB_COMBORETURN("Auto Update", autoupopts, Sys_GetAutoUpdateSetting(), updatecbo, "Hello World"),
MB_SPACING(4),
// removed hud options (cl_sbar, cl_hudswap, old-style chat, old-style msg)
MB_CONSOLECMD("Video Options", "menu_video\n", "Set video resolution, color depth, refresh rate, and anti-aliasing options."),
@ -219,6 +236,9 @@ void M_Menu_Options_f (void)
menu_t *menu = M_Options_Title(&y, 0);
static menuresel_t resel;
MC_AddBulk(menu, &resel, bulk, 16, 216, y);
menu->data = updatecbo;
menu->remove = M_Options_Remove;
}
#ifndef __CYGWIN__
@ -2093,6 +2113,7 @@ void M_Menu_Singleplayer_Cheats_f (void)
#endif
typedef struct {
menucombo_t *dispmode;
menucombo_t *resmode;
menuedit_t *width;
menuedit_t *height;
@ -2114,6 +2135,7 @@ void CheckCustomMode(struct menu_s *menu)
videomenuinfo_t *info = (videomenuinfo_t*)menu->data;
// hide all display controls
info->resmode->common.ishidden = true;
info->width->common.ishidden = true;
info->height->common.ishidden = true;
info->bpp->common.ishidden = true;
@ -2122,20 +2144,24 @@ void CheckCustomMode(struct menu_s *menu)
info->hzfixed->common.ishidden = true;
for (i = 0; i < ASPECT_RATIOS; i++)
info->ressize[i]->common.ishidden = true;
sel = info->resmode->selectedoption;
if (sel < ASPECT_RATIOS)
if (info->dispmode->selectedoption != 2)
{
// unhide appropriate aspect ratio combo and restricted bpp/hz combos
info->bppfixed->common.ishidden = false;
info->hzfixed->common.ishidden = false;
info->ressize[sel]->common.ishidden = false;
}
else if (sel == (ASPECT_RATIOS + 1))
{ // unhide custom entries for custom option
info->width->common.ishidden = false;
info->height->common.ishidden = false;
info->bpp->common.ishidden = false;
info->hz->common.ishidden = false;
info->resmode->common.ishidden = false;
sel = info->resmode->selectedoption;
if (sel < ASPECT_RATIOS)
{
// unhide appropriate aspect ratio combo and restricted bpp/hz combos
info->bppfixed->common.ishidden = false;
info->hzfixed->common.ishidden = false;
info->ressize[sel]->common.ishidden = false;
}
else if (sel == (ASPECT_RATIOS + 1))
{ // unhide custom entries for custom option
info->width->common.ishidden = false;
info->height->common.ishidden = false;
info->bpp->common.ishidden = false;
info->hz->common.ishidden = false;
}
}
// hide all 2d display controls
info->width2d->common.ishidden = true;
@ -2341,6 +2367,14 @@ void M_Menu_Video_f (void)
};
#endif
static const char *fullscreenopts[] = {
"Windowed",
"Fullscreen",
"Borderless Windowed",
NULL
};
static const char *fullscreenvalues[] = {"0", "1", "2", NULL};
static const char *aaopts[] = {
"1x",
"2x",
@ -2443,10 +2477,10 @@ void M_Menu_Video_f (void)
#ifdef MULTIRENDERER
MB_COMBOCVAR("Renderer", vid_renderer, rendererops, renderervalues, NULL),
#endif
MB_CHECKBOXCVAR("Fullscreen", vid_fullscreen, 0),
MB_COMBOCVARRETURN("Display Mode", vid_fullscreen, fullscreenopts, fullscreenvalues, info->dispmode, vid_fullscreen.description),
MB_COMBOCVAR("Anti-aliasing", vid_multisample, aaopts, aavalues, NULL),
MB_REDTEXT(current3dres, false),
MB_COMBORETURN("Display Mode", resmodeopts, resmodechoice, info->resmode, "Select method for determining or configuring display options. The desktop option will attempt to use the width, height, color depth, and refresh from your operating system's desktop environment."),
MB_COMBORETURN("Aspect", resmodeopts, resmodechoice, info->resmode, "Select method for determining or configuring display options. The desktop option will attempt to use the width, height, color depth, and refresh from your operating system's desktop environment."),
// aspect entries
MB_COMBORETURN("Size", resaspects[0], reschoices[0], info->ressize[0], "Select resolution for display."),
MB_SPACING(-8),

View File

@ -14,10 +14,18 @@ typedef struct {
int issave;
int cursorpos;
menutext_t *cursoritem;
int picslot;
shader_t *picshader;
} loadsavemenuinfo_t;
#define MAX_SAVEGAMES 20
char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
struct
{
char map[22+1];
char kills[39-22+1];
char time[64];
} m_saves[MAX_SAVEGAMES];
int loadable[MAX_SAVEGAMES];
void M_ScanSaves (void)
@ -29,30 +37,43 @@ void M_ScanSaves (void)
for (i=0 ; i<MAX_SAVEGAMES ; i++)
{
strcpy (m_filenames[i], "--- UNUSED SLOT ---");
Q_strncpyz (m_saves[i].map, "--- UNUSED SLOT ---", sizeof(m_saves[i].map));
Q_strncpyz (m_saves[i].kills, "", sizeof(m_saves[i].kills));
Q_strncpyz (m_saves[i].time, "", sizeof(m_saves[i].time));
loadable[i] = false;
snprintf (line, sizeof(line), "saves/s%i/info.fsv", i);
f = FS_OpenVFS (line, "rb", FS_GAME);
if (!f)
{ //legacy saved games from some other engine
snprintf (line, sizeof(line), "s%i.sav", i);
f = FS_OpenVFS (line, "rb", FS_GAME);
}
if (f)
{
VFS_GETS(f, line, sizeof(line));
version = atoi(line);
if (version < FTESAVEGAME_VERSION || version >= FTESAVEGAME_VERSION+GT_MAX)
if (version != 5 && version != 6 && (version < FTESAVEGAME_VERSION || version >= FTESAVEGAME_VERSION+GT_MAX))
{
Q_strncpyz (m_filenames[i], "Incompatible version", sizeof(m_filenames[i]));
Q_strncpyz (m_saves[i].map, "Incompatible version", sizeof(m_saves[i].map));
VFS_CLOSE (f);
continue;
}
// read the desc, change _ back to space, fill the separate fields
VFS_GETS(f, line, sizeof(line));
Q_strncpyz (m_filenames[i], line, sizeof(m_filenames[i]));
for (j=0 ; line[j] ; j++)
if (line[j] == '_')
line[j] = ' ';
for (; j < sizeof(line[j]); j++)
line[j] = '\0';
memcpy(m_saves[i].map, line, 22);
m_saves[i].map[22] = 0;
memcpy(m_saves[i].kills, line+22, 39-22);
m_saves[i].kills[22] = 0;
Q_strncpyz(m_saves[i].time, line+39, sizeof(m_saves[i].time));
// change _ back to space
for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
if (m_filenames[i][j] == '_')
m_filenames[i][j] = ' ';
loadable[i] = true;
VFS_CLOSE (f);
@ -61,6 +82,49 @@ void M_ScanSaves (void)
}
}
static void M_Menu_LoadSave_Remove(menu_t *menu)
{
loadsavemenuinfo_t *info = menu->data;
if (info->picshader)
{
Image_UnloadTexture(info->picshader->defaulttextures.base);
R_UnloadShader(info->picshader);
}
}
static void M_Menu_LoadSave_Preview_Draw(int x, int y, menucustom_t *item, menu_t *menu)
{
loadsavemenuinfo_t *info = menu->data;
int slot;
if (!menu->selecteditem)
return;
slot = (menu->selecteditem->common.posy - 32)/8;
if (slot >= 0 && slot < MAX_SAVEGAMES)
{
int width, height;
if (slot != info->picslot || !info->picshader)
{
info->picslot = slot;
if (info->picshader)
{
Image_UnloadTexture(info->picshader->defaulttextures.base);
R_UnloadShader(info->picshader);
}
info->picshader = R_RegisterPic(va("saves/s%i/screeny.tga", slot));
}
if (info->picshader)
{
if (R_GetShaderSizes(info->picshader, &width, &height, false) > 0)
{
//FIXME: maintain aspect
R2D_ScalePic (x, y, 160,120/*item->common.width, item->common.height*/, info->picshader);
}
}
Draw_FunStringWidth(x, y+120+0, m_saves[slot].time, 160, 2, false);
Draw_FunStringWidth(x, y+120+8, m_saves[slot].kills, 160, 2, false);
}
}
void M_Menu_Save_f (void)
{
menuoption_t *op = NULL;
@ -78,6 +142,7 @@ void M_Menu_Save_f (void)
menu = M_CreateMenu(sizeof(loadsavemenuinfo_t));
menu->data = menu+1;
menu->remove = M_Menu_LoadSave_Remove;
MC_AddCenterPicture (menu, 4, 24, "gfx/p_save.lmp");
menu->cursoritem = (menuoption_t *)MC_AddRedText(menu, 8, 0, 32, NULL, false);
@ -86,10 +151,12 @@ void M_Menu_Save_f (void)
for (i=0 ; i< MAX_SAVEGAMES; i++)
{
op = (menuoption_t *)MC_AddConsoleCommandf(menu, 16, 170, 32+8*i, m_filenames[i], "savegame s%i\nclosemenu\n", i);
op = (menuoption_t *)MC_AddConsoleCommandf(menu, 16, 192, 32+8*i, false, m_saves[i].map, "savegame s%i\nclosemenu\n", i);
if (!menu->selecteditem)
menu->selecteditem = op;
}
MC_AddCustom(menu, 192, 60-16, NULL, 0)->draw = M_Menu_LoadSave_Preview_Draw;
}
void M_Menu_Load_f (void)
{
@ -105,18 +172,21 @@ void M_Menu_Load_f (void)
MC_AddCenterPicture(menu, 4, 24, "gfx/p_load.lmp");
menu->cursoritem = (menuoption_t *)MC_AddRedText(menu, 8, 0, 32, NULL, false);
menu->remove = M_Menu_LoadSave_Remove;
M_ScanSaves ();
for (i=0 ; i< MAX_SAVEGAMES; i++)
{
if (loadable[i])
op = (menuoption_t *)MC_AddConsoleCommandf(menu, 16, 170, 32+8*i, m_filenames[i], "loadgame s%i\nclosemenu\n", i);
op = (menuoption_t *)MC_AddConsoleCommandf(menu, 16, 170, 32+8*i, false, m_saves[i].map, "loadgame s%i\nclosemenu\n", i);
else
MC_AddWhiteText(menu, 16, 170, 32+8*i, m_filenames[i], false);
MC_AddWhiteText(menu, 16, 170, 32+8*i, m_saves[i].map, false);
if (!menu->selecteditem && op)
menu->selecteditem = op;
}
MC_AddCustom(menu, 192, 60-16, NULL, 0)->draw = M_Menu_LoadSave_Preview_Draw;
}

View File

@ -669,6 +669,8 @@ static qboolean M_Menu_Prompt_Button (union menuoption_s *b,struct menu_s *gm, i
{
int action;
promptmenu_t *m = (promptmenu_t*)gm;
void (*callback)(void *, int) = m->callback;
void *ctx = m->ctx;
if (key != K_ENTER && key != K_KP_ENTER && key != K_MOUSE1)
return true;
@ -679,19 +681,23 @@ static qboolean M_Menu_Prompt_Button (union menuoption_s *b,struct menu_s *gm, i
action = 1;
else //if (b == (menuoption_t*)m->b_cancel)
action = -1;
if (m->callback)
m->callback(m->ctx, action);
m->callback = NULL;
M_RemoveMenu(&m->m);
if (callback)
callback(ctx, action);
return true;
}
static void M_Menu_Prompt_Cancel (struct menu_s *gm)
{
promptmenu_t *m = (promptmenu_t*)gm;
if (m->callback)
m->callback(m->ctx, -1);
void (*callback)(void *, int) = m->callback;
void *ctx = m->ctx;
m->callback = NULL;
if (callback)
callback(ctx, -1);
}
void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, char *m1, char *m2, char *m3, char *optionyes, char *optionno, char *optioncancel)
{

View File

@ -162,6 +162,7 @@ typedef struct {
menucommon_t common;
const char *text;
const char *command;
qboolean rightalign;
qboolean (*key) (union menuoption_s *option, struct menu_s *, int key);
} menubutton_t;
@ -317,7 +318,7 @@ menubutton_t *MC_AddConsoleCommand(menu_t *menu, int lhs, int rhs, int y, const
menubutton_t *MC_AddConsoleCommandQBigFont(menu_t *menu, int x, int y, const char *text, const char *command);
mpic_t *QBigFontWorks(void);
menubutton_t *MC_AddConsoleCommandHexen2BigFont(menu_t *menu, int x, int y, const char *text, const char *command);
menubutton_t *VARGS MC_AddConsoleCommandf(menu_t *menu, int lhs, int rhs, int y, const char *text, char *command, ...);
menubutton_t *VARGS MC_AddConsoleCommandf(menu_t *menu, int lhs, int rhs, int y, qboolean rightalign, const char *text, char *command, ...);
menubutton_t *MC_AddCommand(menu_t *menu, int lhs, int rhs, int y, char *text, qboolean (*command) (union menuoption_s *,struct menu_s *,int));
menucombo_t *MC_AddCombo(menu_t *menu, int tx, int cx, int y, const char *caption, const char **ops, int initialvalue);
menucombo_t *MC_AddCvarCombo(menu_t *menu, int tx, int cx, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values);

View File

@ -2018,7 +2018,7 @@ static model_t *csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int mode
{
if (modelindex <= -MAX_CSMODELS)
return NULL;
ent->v->model = PR_SetString(prinst, cl.model_csqcname[-modelindex]);
prinst->SetStringField(prinst, (void*)ent, &ent->v->model, cl.model_csqcname[-modelindex], true);
if (!cl.model_csqcprecache[-modelindex])
cl.model_csqcprecache[-modelindex] = Mod_ForName(Mod_FixName(cl.model_csqcname[-modelindex], csqc_world.worldmodel->name), MLV_WARN);
model = cl.model_csqcprecache[-modelindex];
@ -2027,7 +2027,7 @@ static model_t *csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int mode
{
if (modelindex >= MAX_PRECACHE_MODELS)
return NULL;
ent->v->model = PR_SetString(prinst, cl.model_name[modelindex]);
prinst->SetStringField(prinst, (void*)ent, &ent->v->model, cl.model_name[modelindex], true);
model = cl.model_precache[modelindex];
}
if (model)
@ -4827,11 +4827,11 @@ static struct {
{"fputs", PF_fputs, 113}, // #113 void(float fnum, string str) fputs (FRIK_FILE)
{"strlen", PF_strlen, 114}, // #114 float(string str) strlen (FRIK_FILE)
{"strcat", PF_strcat, 115}, // #115 string(string str1, string str2, ...) strcat (FRIK_FILE)
{"strcat", PF_strcat, 115}, // #115 string(string str1, string str2, ...) strcat (FRIK_FILE)
{"substring", PF_substring, 116}, // #116 string(string str, float start, float length) substring (FRIK_FILE)
{"stov", PF_stov, 117}, // #117 vector(string str) stov (FRIK_FILE)
{"strzone", PF_dupstring, 118}, // #118 string(string str) dupstring (FRIK_FILE)
{"strunzone", PF_forgetstring, 119}, // #119 void(string str) freestring (FRIK_FILE)
{"stov", PF_stov, 117}, // #117 vector(string str) stov (FRIK_FILE)
{"strzone", PF_strzone, 118}, // #118 string(string str) dupstring (FRIK_FILE)
{"strunzone", PF_strunzone, 119}, // #119 void(string str) freestring (FRIK_FILE)
//200
{"getmodelindex", PF_cs_PrecacheModel, 200},
@ -5501,7 +5501,7 @@ void CSQC_Shutdown(void)
{
key_dest_absolutemouse &= ~kdm_game;
CSQC_ForgetThreads();
PR_ResetFonts(kdm_game);
PR_ReleaseFonts(kdm_game);
PR_Common_Shutdown(csqcprogs, false);
csqcprogs->CloseProgs(csqcprogs);
}
@ -5920,7 +5920,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
/*DP compat*/
str = (string_t*)csqcprogs->GetEdictFieldValue(csqcprogs, (edict_t*)worldent, "message", NULL);
if (str)
*str = PR_SetString(csqcprogs, cl.levelname);
*str = PR_NewString(csqcprogs, cl.levelname);
str = (string_t*)PR_FindGlobal(csqcprogs, "mapname", 0, NULL);
if (str)
@ -5928,7 +5928,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
char *s = Info_ValueForKey(cl.serverinfo, "map");
if (!*s)
s = "unknown";
*str = PR_NewString(csqcprogs, s, strlen(s)+1);
*str = PR_NewString(csqcprogs, s);
}
if (csqcg.init_function)

View File

@ -136,17 +136,19 @@ int PR_findnamedfont(const char *name, qboolean isslotname)
}
return -1;
}
//purgeowner 0 will reload all fonts. other values will purge only fonts which are now unused.
void PR_ResetFonts(unsigned int purgeowner)
//purgeowner is the bitmask of owners that are getting freed.
//if purgeowner is 0, fonts will get purged
void PR_ReleaseFonts(unsigned int purgeowner)
{
int i, j;
for (i = 0; i < FONT_SLOTS; i++)
{
if (fontslot[i].owner)
continue; //already free
fontslot[i].owner &= ~purgeowner;
//don't bother flushing fonts when we don't really need to.
if (fontslot[i].owner && purgeowner)
return;
if (fontslot[i].owner)
continue; //still owned by someone
for (j = 0; j < fontslot[i].sizes; j++)
{
@ -155,21 +157,37 @@ void PR_ResetFonts(unsigned int purgeowner)
fontslot[i].font[j] = NULL;
}
//if noone is interested in it now, it can be purged fully.
fontslot[i].sizes = 0;
fontslot[i].slotname[0] = '\0';
fontslot[i].facename[0] = '\0';
}
}
void PR_ReloadFonts(qboolean reload)
{
int i, j;
if (qrenderer == QR_NONE)
reload = false;
for (i = 0; i < FONT_SLOTS; i++)
{
//already not loaded
if (!fontslot[i].owner)
continue;
//flush it (if loaded)
for (j = 0; j < fontslot[i].sizes; j++)
{
fontslot[i].sizes = 0;
fontslot[i].slotname[0] = '\0';
fontslot[i].facename[0] = '\0';
if (fontslot[i].font[j])
Font_Free(fontslot[i].font[j]);
fontslot[i].font[j] = NULL;
}
else
//and reload if needed
if (reload)
{ //otherwise load it.
for (j = 0; j < fontslot[i].sizes; j++)
{
if (qrenderer == QR_NONE)
fontslot[i].font[j] = NULL;
else
fontslot[i].font[j] = Font_LoadFont(fontslot[i].size[j], fontslot[i].facename);
fontslot[i].font[j] = Font_LoadFont(fontslot[i].size[j], fontslot[i].facename);
}
}
}
@ -340,12 +358,15 @@ void CL_LoadFont_f(void)
}
}
//scrolling could be done with scissoring.
//selection could be done with some substrings
void QCBUILTIN PF_CL_DrawTextField (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float *pos = G_VECTOR(OFS_PARM0);
float *size = G_VECTOR(OFS_PARM1);
unsigned int flags = G_FLOAT(OFS_PARM2);
const char *text = PR_GetStringOfs(prinst, OFS_PARM3);
R_DrawTextField(pos[0], pos[1], size[0], size[1], text, CON_WHITEMASK, flags);
}
@ -931,20 +952,6 @@ cvar_t pr_menuqc_coreonerror = SCVAR("pr_menuqc_coreonerror", "1");
//new generic functions.
void QCBUILTIN PF_mod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int a = G_FLOAT(OFS_PARM0);
int b = G_FLOAT(OFS_PARM1);
if (b == 0)
{
Con_Printf("mod by zero\n");
prinst->pr_trace = 1;
G_FLOAT(OFS_RETURN) = 0;
}
else
G_FLOAT(OFS_RETURN) = a % b;
}
const char *RemapCvarNameFromDPToFTE(const char *name)
{
if (!stricmp(name, "vid_bitsperpixel"))
@ -1716,8 +1723,8 @@ static struct {
{"strcat", PF_strcat, 53},
{"substring", PF_substring, 54},
{"stov", PF_stov, 55},
{"strzone", PF_dupstring, 56},
{"strunzone", PF_forgetstring, 57},
{"strzone", PF_strzone, 56},
{"strunzone", PF_strunzone, 57},
{"tokenize", PF_Tokenize, 58},
{"argv", PF_ArgV, 59},
{"isserver", PF_isserver, 60},
@ -2014,7 +2021,7 @@ void MP_Shutdown (void)
PR_Common_Shutdown(menu_world.progs, false);
menu_world.progs->CloseProgs(menu_world.progs);
memset(&menu_world, 0, sizeof(menu_world));
PR_ResetFonts(kdm_menu);
PR_ReleaseFonts(kdm_menu);
#ifdef CL_MASTER
Master_ClearMasks();

View File

@ -130,6 +130,10 @@ void R2D_Shutdown(void)
if (font_tiny)
Font_Free(font_tiny);
font_tiny = NULL;
#if defined(MENU_DAT) || defined(CSQC_DAT)
PR_ReloadFonts(false);
#endif
}
/*
@ -716,7 +720,7 @@ void R2D_Font_Changed(void)
font_tiny = NULL;
#if defined(MENU_DAT) || defined(CSQC_DAT)
PR_ResetFonts(0);
PR_ReloadFonts(true);
#endif
if (qrenderer == QR_NONE)

View File

@ -386,6 +386,7 @@ enum imageflags
image_t *Image_FindTexture (const char *identifier, const char *subpath, unsigned int flags);
image_t *Image_CreateTexture(const char *identifier, const char *subpath, unsigned int flags);
image_t *Image_GetTexture (const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt);
qboolean Image_UnloadTexture (image_t *tex); //true if it did something.
void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags);
void Image_Init(void);
void Image_Shutdown(void);

View File

@ -929,10 +929,6 @@ qbyte default_quakepal[768] =
51,67,51,39,55,43,31,39,31,23,27,19,15,15,11,7,111,131,123,103,123,111,95,115,103,87,107,95,79,99,87,71,91,79,63,83,71,55,75,63,47,67,55,43,59,47,35,51,39,31,43,31,23,35,23,15,27,19,11,19,11,7,11,7,255,243,27,239,223,23,219,203,19,203,183,15,187,167,15,171,151,11,155,131,7,139,115,7,123,99,7,107,83,0,91,71,0,75,55,0,59,43,0,43,31,0,27,15,0,11,7,0,0,0,255,11,11,239,19,19,223,27,27,207,35,35,191,43,
43,175,47,47,159,47,47,143,47,47,127,47,47,111,47,47,95,43,43,79,35,35,63,27,27,47,19,19,31,11,11,15,43,0,0,59,0,0,75,7,0,95,7,0,111,15,0,127,23,7,147,31,7,163,39,11,183,51,15,195,75,27,207,99,43,219,127,59,227,151,79,231,171,95,239,191,119,247,211,139,167,123,59,183,155,55,199,195,55,231,227,87,127,191,255,171,231,255,215,255,255,103,0,0,139,0,0,179,0,0,215,0,0,255,0,0,255,243,147,255,247,199,255,255,255,159,91,83
};
qbyte default_conchar[11356] =
{
#include "lhfont.h"
};
qboolean R_ApplyRenderer_Load (rendererstate_t *newr);
void D3DSucks(void)
@ -975,6 +971,7 @@ void R_ShutdownRenderer(qboolean videotoo)
COM_FlushTempoaryPacks();
Skin_FlushAll();
W_Shutdown();
if (h2playertranslations)
BZ_Free(h2playertranslations);
@ -1449,6 +1446,36 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring)
}
}
}
else if (!strcmp(com_token, "random"))
{
int count;
for (i = 0, count = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)
{
if (!rendererinfo[i]->description)
continue; //not valid in this build. :(
if (rendererinfo[i]->rtype == QR_NONE || //dedicated servers are not useful
rendererinfo[i]->rtype == QR_HEADLESS || //headless appears buggy
rendererinfo[i]->rtype == QR_SOFTWARE ) //software is just TOO buggy/limited for us to care.
continue;
count++;
}
count = rand()%count;
for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)
{
if (!rendererinfo[i]->description)
continue; //not valid in this build. :(
if (rendererinfo[i]->rtype == QR_NONE ||
rendererinfo[i]->rtype == QR_HEADLESS ||
rendererinfo[i]->rtype == QR_SOFTWARE )
continue;
if (!count--)
{
newr->renderer = rendererinfo[i];
Con_Printf("randomly selected renderer: %s\n", rendererinfo[i]->description);
break;
}
}
}
else
{
for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)

View File

@ -203,10 +203,21 @@ void Draw_FunStringWidth(float x, float y, const void *str, int width, qboolean
{
fw += Font_CharWidth(*w);
}
px += width;
if (fw > width)
fw = width;
px -= fw;
if (rightalign == 2)
{
if (fw < width)
{
px += (width-fw)/2;
width = fw;
}
}
else
{
px += width;
if (fw > width)
fw = width;
px -= fw;
}
}
for (w = buffer; *w; w++)
@ -2645,6 +2656,8 @@ void Sbar_Draw (playerview_t *pv)
{
if (!cl.spectator || pv->cam_auto == CAM_TRACK)
Sbar_DrawInventory (pv);
else if (cl_sbar.ival)
Sbar_DrawPic (0, -24, 320, 24, sb_scorebar); //make sure we don't get HoM
if ((!headsup || sbar_rect.width<512) && cl.deathmatch)
Sbar_DrawFrags (pv);
}
@ -3401,7 +3414,7 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
Font_BeginString(font_default, x+24, y, &px, &py);
Font_DrawChar ( px, py, num[2] | 0xe000 | CON_WHITEMASK);
if ((cl.spectator && k == pv->cam_spec_track) ||
if ((cl.spectator && k == pv->cam_spec_track && pv->cam_locked) ||
(!cl.spectator && k == pv->playernum))
{
Font_BeginString(font_default, x, y, &px, &py);

View File

@ -120,7 +120,8 @@ void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end);
extern struct font_s *font_default;
extern struct font_s *font_console;
extern struct font_s *font_tiny;
void PR_ResetFonts(unsigned int purgeowner); //for menu/csqc
void PR_ReleaseFonts(unsigned int purgeowner); //for menu/csqc
void PR_ReloadFonts(qboolean reload);
/*end fonts*/
void R_NetgraphInit(void);

View File

@ -720,3 +720,12 @@ void Sys_Sleep (double seconds)
}
#ifdef HAVEAUTOUPDATE
int Sys_GetAutoUpdateSetting(void);
{
return -1;
}
void Sys_SetAutoUpdateSetting(int newval)
{
}
#endif

View File

@ -306,6 +306,15 @@ unsigned int sys_parenttop;
unsigned int sys_parentwidth; //valid if sys_parentwindow is set
unsigned int sys_parentheight;
static struct
{
int width;
int height;
int rate;
int bpp;
} desktopsettings;
static void Sys_QueryDesktopParameters(void);
//used to do special things with awkward windows versions.
int qwinvermaj;
int qwinvermin;
@ -1328,6 +1337,8 @@ void Sys_Init (void)
// unsigned int lowpart, highpart;
OSVERSIONINFO vinfo;
Sys_QueryDesktopParameters();
#ifndef SERVERONLY
Cvar_Register(&sys_disableWinKeys, "System vars");
Cvar_Register(&sys_disableTaskSwitch, "System vars");
@ -2476,7 +2487,6 @@ void Win7_TaskListInit(void)
}
}
#if defined(SVNREVISION) && !defined(MINIMAL)
#define SVNREVISIONSTR STRINGIFY(SVNREVISION)
#if defined(OFFICIAL_RELEASE)
@ -2485,12 +2495,14 @@ void Win7_TaskListInit(void)
#define UPD_BUILDTYPE "test"
//WARNING: Security comes from the fact that the triptohell.info certificate is hardcoded in the tls code.
//this will correctly detect insecure tls proxies also.
#define UPDATE_URL "https://triptohell.info/moodles/"
#define UPDATE_URL_VERSION UPDATE_URL "version.txt"
#define UPDATE_URL_ROOT "https://triptohell.info/moodles/"
#define UPDATE_URL_TESTED UPDATE_URL_ROOT "autoup/"
#define UPDATE_URL_NIGHTLY UPDATE_URL_ROOT
#define UPDATE_URL_VERSION "%sversion.txt"
#ifdef _WIN64
#define UPDATE_URL_BUILD UPDATE_URL "win64/fte" EXETYPE "64.exe"
#define UPDATE_URL_BUILD "%swin64/fte" EXETYPE "64.exe"
#else
#define UPDATE_URL_BUILD UPDATE_URL "win32/fte" EXETYPE ".exe"
#define UPDATE_URL_BUILD "%swin32/fte" EXETYPE ".exe"
#endif
#endif
#endif
@ -2609,7 +2621,9 @@ void MyRegDeleteKeyValue(HKEY base, char *keyname, char *valuename)
RegCloseKey (subkey);
}
}
#ifdef UPDATE_URL
#ifdef UPDATE_URL_ROOT
int sys_autoupdatesetting;
qboolean Update_GetHomeDirectory(char *homedir, int homedirsize)
{
@ -2649,8 +2663,30 @@ static void Update_CreatePath (char *path)
}
}
void Update_UserAcked(void *ctx, int foo)
//ctx is a pointer to the original frontend process
void Update_PromptedDownloaded(void *ctx, int foo)
{
if (foo == 0 && ctx)
{
PROCESS_INFORMATION childinfo;
STARTUPINFO startinfo = {sizeof(startinfo)};
#ifndef SERVERONLY
SetHookState(false);
Host_Shutdown ();
CloseHandle (qwclsemaphore);
SetHookState(false);
#else
SV_Shutdown();
#endif
TL_Shutdown();
CreateProcess(ctx, va("\"%s\" %s", ctx, COM_Parse(GetCommandLineA())), NULL, NULL, TRUE, 0, NULL, NULL, &startinfo, &childinfo);
Z_Free(ctx);
exit(1);
}
else
Z_Free(ctx);
}
#include "fs.h"
@ -2685,8 +2721,19 @@ void Update_Version_Updated(struct dl_download *dl)
Con_Printf("Download was the wrong size / corrupt\n");
else
{
//figure out the original binary that was executed, so we can start from scratch.
//this is to attempt to avoid the new process appearing as 'foo.tmp'. which needlessly confuses firewall rules etc.
int ffe = COM_CheckParm("--fromfrontend");
char binarypath[MAX_PATH];
char *ffp;
GetModuleFileName(NULL, binarypath, sizeof(binarypath)-1);
ffp = Z_StrDup(ffe?com_argv[ffe+2]:binarypath);
//make it pending
MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" UPD_BUILDTYPE EXETYPE, REG_SZ, pendingname, strlen(pendingname)+1);
M_Menu_Prompt(Update_UserAcked, NULL, "An update was downloaded", "Restart to activate.", "", "", "", "Okay");
Key_Dest_Remove(kdm_console);
M_Menu_Prompt(Update_PromptedDownloaded, ffp, "An update was downloaded", "Restart to activate.", "", ffp?"Restart":NULL, "", "Okay");
}
}
}
@ -2694,6 +2741,21 @@ void Update_Version_Updated(struct dl_download *dl)
Con_Printf("Update download failed\n");
}
}
void Update_PromptedForUpdate(void *ctx, int foo)
{
if (foo == 0)
{
struct dl_download *dl;
Con_Printf("Downloading update\n");
dl = HTTP_CL_Get(va(UPDATE_URL_BUILD, ctx), NULL, Update_Version_Updated);
dl->file = FS_OpenTemp();
#ifdef MULTITHREAD
DL_CreateThread(dl, NULL, NULL);
#endif
}
else
Con_Printf("Not downloading update\n");
}
void Update_Versioninfo_Available(struct dl_download *dl)
{
if (dl->file)
@ -2707,13 +2769,17 @@ void Update_Versioninfo_Available(struct dl_download *dl)
{
if (atoi(linebuf+10) > atoi(SVNREVISIONSTR))
{
struct dl_download *dl;
Con_Printf("Downloading update: revision %i\n", atoi(linebuf+10));
dl = HTTP_CL_Get(UPDATE_URL_BUILD, NULL, Update_Version_Updated);
dl->file = FS_OpenTemp();
#ifdef MULTITHREAD
DL_CreateThread(dl, NULL, NULL);
#endif
char *revision = va("Revision %i", atoi(linebuf+10));
char *current = va("Current %i", atoi(SVNREVISIONSTR));
Con_Printf("An update is available, revision %i\n", atoi(linebuf+10));
if (COM_CheckParm("-autoupdate") || COM_CheckParm("--autoupdate"))
Update_PromptedForUpdate(dl->user_ctx, 0);
else
{
Key_Dest_Remove(kdm_console);
M_Menu_Prompt(Update_PromptedForUpdate, dl->user_ctx, "An update is available.", revision, current, "Download", "", "Ignore");
}
}
else
Con_Printf("autoupdate: already at latest version\n");
@ -2723,32 +2789,67 @@ void Update_Versioninfo_Available(struct dl_download *dl)
}
}
}
static qboolean doupdatecheck;
void Update_Check(void)
{
static qboolean doneupdatecheck; //once per run
struct dl_download *dl;
if (doupdatecheck)
if (sys_autoupdatesetting < 2) //not if disabled (do it once it does get enabled)
return;
if (!doneupdatecheck)
{
doupdatecheck = false;
dl = HTTP_CL_Get(UPDATE_URL_VERSION, NULL, Update_Versioninfo_Available);
char *updateroot = (sys_autoupdatesetting>=3)?UPDATE_URL_NIGHTLY:UPDATE_URL_TESTED;
doneupdatecheck = true;
dl = HTTP_CL_Get(va(UPDATE_URL_VERSION, updateroot), NULL, Update_Versioninfo_Available);
dl->file = FS_OpenTemp();
dl->user_ctx = updateroot;
#ifdef MULTITHREAD
DL_CreateThread(dl, NULL, NULL);
#endif
}
}
int Sys_GetAutoUpdateSetting(void)
{
return sys_autoupdatesetting;
}
void Sys_SetAutoUpdateSetting(int newval)
{
static qboolean doneupdatecheck;
if (sys_autoupdatesetting == newval)
return;
sys_autoupdatesetting = newval;
MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "AutoUpdateEnabled", REG_DWORD, &sys_autoupdatesetting, sizeof(sys_autoupdatesetting));
Update_Check();
}
qboolean Sys_CheckUpdated(void)
{
int ffe = COM_CheckParm("--fromfrontend");
PROCESS_INFORMATION childinfo;
STARTUPINFO startinfo = {sizeof(startinfo)};
char *e;
strtoul(SVNREVISIONSTR, &e, 10);
if (!*SVNREVISIONSTR || *e) //svn revision didn't parse as an exact number. this implies it has an 'M' in it to mark it as modified, or a - to mean unknown. either way, its bad and autoupdates when we don't know what we're updating from is a bad idea.
sys_autoupdatesetting = -1;
else if (COM_CheckParm("-noupdate") || COM_CheckParm("--noupdate") || COM_CheckParm("-noautoupdate") || COM_CheckParm("--noautoupdate"))
sys_autoupdatesetting = 0;
else if (COM_CheckParm("-autoupdate") || COM_CheckParm("--autoupdate"))
sys_autoupdatesetting = 3;
else
{
//favour 'tested'
sys_autoupdatesetting = MyRegGetIntValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "AutoUpdateEnabled", 2);
}
if (!strcmp(SVNREVISIONSTR, "-"))
return false; //no revision info in this build, meaning its custom built and thus cannot check against the available updated versions.
else if (COM_CheckParm("-noupdate") || COM_CheckParm("--noupdate"))
return false;
else if (!COM_CheckParm("-autoupdate") && !COM_CheckParm("--autoupdate"))
else if (sys_autoupdatesetting == 0)
return false;
else if (isPlugin == 1)
{
@ -2756,7 +2857,7 @@ qboolean Sys_CheckUpdated(void)
}
else if (!ffe)
{
//if we're not from the frontend, we should run the updated build instead
//if we're not from the frontend (ie: we ARE the frontend), we should run the updated build instead
char frontendpath[MAX_OSPATH];
char pendingpath[MAX_OSPATH];
char updatedpath[MAX_OSPATH];
@ -2765,12 +2866,20 @@ qboolean Sys_CheckUpdated(void)
MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" UPD_BUILDTYPE EXETYPE, pendingpath, sizeof(pendingpath));
if (*pendingpath)
{
qboolean okay;
MyRegDeleteKeyValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" UPD_BUILDTYPE EXETYPE);
Update_GetHomeDirectory(updatedpath, sizeof(updatedpath));
Update_CreatePath(updatedpath);
Q_strncatz(updatedpath, "cur" UPD_BUILDTYPE EXETYPE".exe", sizeof(updatedpath));
DeleteFile(updatedpath);
if (MoveFile(pendingpath, updatedpath))
okay = MoveFile(pendingpath, updatedpath);
if (!okay)
{ //if we just downloaded an update, we may need to wait for the existing process to close.
//sadly I'm too lazy to provide any sync mechanism (and wouldn't trust any auto-released handles or whatever), so lets just retry after a delay.
Sleep(2000);
okay = MoveFile(pendingpath, updatedpath);
}
if (okay)
MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, UPD_BUILDTYPE EXETYPE, REG_SZ, updatedpath, strlen(updatedpath)+1);
else
{
@ -2803,10 +2912,16 @@ qboolean Sys_CheckUpdated(void)
if (com_argv[ffe+2])
com_argv[0] = com_argv[ffe+2];
}
doupdatecheck = true;
return false;
}
#else
int Sys_GetAutoUpdateSetting(void)
{
return -1;
}
void Sys_SetAutoUpdateSetting(int newval)
{
}
qboolean Sys_CheckUpdated(void)
{
return false;
@ -3443,26 +3558,31 @@ int __cdecl main(void)
return WinMain(GetModuleHandle(NULL), NULL, cmdline, SW_NORMAL);
}
//now queries at startup and then caches, to avoid mode changes from giving weird results.
qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate)
{
*width = desktopsettings.width;
*height = desktopsettings.height;
*bpp = desktopsettings.bpp;
*refreshrate = desktopsettings.rate;
return true;
}
static void Sys_QueryDesktopParameters(void)
{
HDC hdc;
int rate;
hdc = GetDC(NULL);
*width = GetDeviceCaps(hdc, HORZRES);
*height = GetDeviceCaps(hdc, VERTRES);
*bpp = GetDeviceCaps(hdc, BITSPIXEL);
rate = GetDeviceCaps(hdc, VREFRESH);
desktopsettings.width = GetDeviceCaps(hdc, HORZRES);
desktopsettings.height = GetDeviceCaps(hdc, VERTRES);
desktopsettings.bpp = GetDeviceCaps(hdc, BITSPIXEL);
desktopsettings.rate = GetDeviceCaps(hdc, VREFRESH);
if (rate == 1)
rate = 0;
*refreshrate = rate;
if (desktopsettings.rate == 1)
desktopsettings.rate = 0;
ReleaseDC(NULL, hdc);
return true;
}
void Sys_Sleep (double seconds)

View File

@ -31,7 +31,7 @@ typedef struct {
//you are not allowed to make anything not work if it's not based on these vars...
int width;
int height;
qboolean fullscreen;
int fullscreen; //0 = windowed. 1 = fullscreen (mode changes). 2 = borderless+maximized
qboolean stereo;
qboolean srgb;
int bpp;

View File

@ -1282,7 +1282,7 @@ void V_CalcRefdef (playerview_t *pv)
if (pv->stats[STAT_HEALTH] < 0 && pv->cam_spec_track >= 0 && v_deathtilt.value) // PF_GIB will also set PF_DEAD
{
if (!cl.spectator || !cl_chasecam.ival)
if (!cl.spectator || cl_chasecam.ival)
r_refdef.viewangles[ROLL] = 80*v_deathtilt.value; // dead view angle
}
else
@ -1312,9 +1312,16 @@ void V_CalcRefdef (playerview_t *pv)
//r_refdef.viewangles[0] += chase_pitch.value;
//r_refdef.viewangles[1] += chase_yaw.value;
//r_refdef.viewangles[2] += chase_roll.value;
if (chase_active.ival >= 2)
r_refdef.viewangles[0] = 90;
if (chase_active.ival >= 3)
r_refdef.viewangles[1] = 0;
AngleVectors(r_refdef.viewangles, axis[0], axis[1], axis[2]);
VectorScale(axis[0], -chase_back.value, camdir);
VectorMA(camdir, -chase_up.value, pv->gravitydir, camdir);
if (pv->pmovetype == PM_6DOF)
VectorMA(camdir, chase_up.value, axis[2], camdir);
else
VectorMA(camdir, -chase_up.value, pv->gravitydir, camdir);
len = VectorLength(camdir);
VectorMA(r_refdef.vieworg, (len+128)/len, camdir, camorg); //push it 128qu further
if (cl.worldmodel && cl.worldmodel->funcs.NativeTrace)
@ -1445,6 +1452,7 @@ void SCR_VRectForPlayer(vrect_t *vrect, int pnum)
}
}
#include "pr_common.h"
void Draw_ExpandedString(float x, float y, conchar_t *str);
extern vec3_t nametagorg[MAX_CLIENTS];
extern qboolean nametagseen[MAX_CLIENTS];
@ -1457,6 +1465,57 @@ void R_DrawNameTags(void)
vec3_t tagcenter;
lerpents_t *le;
extern cvar_t r_showbboxes;
if (r_showbboxes.ival && cls.allow_cheats)
{
world_t *w = NULL;
wedict_t *e;
vec3_t org;
vec3_t screenspace;
vec3_t diff;
if (r_showbboxes.ival == 1)
{
#ifndef CLIENTONLY
w = &sv.world;
#endif
}
else if (r_showbboxes.ival == 2)
{
#ifdef CSQC_DAT
extern world_t csqc_world;
w = &csqc_world;
#endif
}
if (w && w->progs)
for (i = 1; i < w->num_edicts; i++)
{
e = WEDICT_NUM(w->progs, i);
if (e->isfree)
continue;
VectorInterpolate(e->v->absmin, 0.5, e->v->absmax, org);
VectorSubtract(org, r_refdef.vieworg, diff);
if (DotProduct(diff, diff) > 256*256)
continue;
if (Matrix4x4_CM_Project(org, screenspace, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y))
{
char asciibuffer[8192];
char *entstr;
int buflen;
int x, y;
buflen = 0;
entstr = w->progs->saveent(w->progs, asciibuffer, &buflen, sizeof(asciibuffer), (edict_t*)e); //will save just one entities vars
if (entstr)
{
x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x;
y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y;
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN);
}
}
}
}
if (!cl.spectator && !cls.demoplayback)
return;
if (!scr_autoid.ival)

View File

@ -101,7 +101,7 @@ extern qboolean mouseinitialized;
void INS_UpdateClipCursor (void);
void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify);
void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int pnum);
void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int pnum, qboolean genkeystate);
void S_BlockSound (void);
void S_UnblockSound (void);

View File

@ -243,7 +243,7 @@ void QDECL Q_strncpyz(char*d, const char*s, int n);
#define Q_strncatz(dest, src, sizeofdest) \
do { \
strncat(dest, src, sizeofdest - strlen(dest) - 1); \
dest[sizeofdest - 1] = 0; \
(dest)[sizeofdest - 1] = 0; \
} while (0)
#define Q_strncatz2(dest, src) Q_strncatz(dest, src, sizeof(dest))
#endif

View File

@ -198,7 +198,7 @@ unsigned int Net_PextMask(int maskset, qboolean fornq)
if (pext_replacementdeltas.ival)
mask |= PEXT2_REPLACEMENTDELTAS;
if (fornq && pext_nqpredinfo.ival)
if (/*fornq &&*/ pext_nqpredinfo.ival)
mask |= PEXT2_PREDINFO;
if (MAX_CLIENTS != QWMAX_CLIENTS)
@ -213,8 +213,8 @@ unsigned int Net_PextMask(int maskset, qboolean fornq)
//only ones that are tested
mask &= PEXT2_VOICECHAT | PEXT2_REPLACEMENTDELTAS | PEXT2_PREDINFO;
}
else
mask &= ~PEXT2_PREDINFO;
// else
// mask &= ~PEXT2_PREDINFO;
}
return mask;

View File

@ -840,8 +840,39 @@ void PM_CategorizePosition (void)
vec3_t tmin,tmax;
VectorCopy(pmove.player_mins, tmin);
VectorCopy(pmove.player_maxs, tmax);
VectorMA(pmove.origin, -48, up, point);
trace = PM_TraceLine(pmove.origin, point);
// //try tracing forwards+down
// VectorMA(pmove.origin, -48, up, point);
// VectorMA(point, 48, forward, point);
// trace = PM_TraceLine(pmove.origin, point);
// trace.fraction = 1;
if (1)//trace.fraction == 1)
{ //getting desparate
VectorMA(pmove.origin, -48, up, point);
VectorMA(point, 48, forward, point);
trace = PM_TraceLine(pmove.origin, point);
}
if (trace.fraction == 1)
{
//try tracing directly down only (we may be stepping off a cliff)
VectorMA(pmove.origin, -48, up, point);
trace = PM_TraceLine(pmove.origin, point);
}
if (trace.fraction == 1)
{
vec3_t point2;
//try tracing back from the cliff to see if we can find the ground beyond
VectorMA(point, 48, forward, point2);
VectorMA(point2, 48, forward, point);
trace = PM_TraceLine(point2, point);
}
if (trace.fraction == 1)
{ //getting desparate
VectorMA(pmove.origin, -48, up, point);
VectorMA(point, -48, forward, point);
trace = PM_TraceLine(pmove.origin, point);
}
VectorCopy(tmin, pmove.player_mins);
VectorCopy(tmax, pmove.player_maxs);

View File

@ -527,8 +527,8 @@ trace_t PM_PlayerTrace (vec3_t start, vec3_t end, unsigned int solidmask)
}
// //this is needed to avoid *2 friction. some id bug.
// if (total.startsolid)
// total.fraction = 0;
if (total.startsolid)
total.fraction = 0;
return total;
}

View File

@ -1665,7 +1665,8 @@ qboolean QC_FixFileName(const char *name, const char **result, const char **fall
{
char ext[8];
if (strchr(name, ':') || //dos/win absolute path, ntfs ADS, amiga drives. reject them all.
if (!*name || //blank names are bad
strchr(name, ':') || //dos/win absolute path, ntfs ADS, amiga drives. reject them all.
strchr(name, '\\') || //windows-only paths.
*name == '/' || //absolute path was given - reject
strstr(name, "..")) //someone tried to be clever.
@ -1731,11 +1732,16 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
VFS_READ(f, pf_fopen_files[i].data, pf_fopen_files[i].len);
VFS_CLOSE(f);
}
else
else if (fmode == FRIK_FILE_MMAP_RW)
{
pf_fopen_files[i].bufferlen = fsize;
pf_fopen_files[i].data = PR_AddressableAlloc(prinst, pf_fopen_files[i].bufferlen);
}
else
{
pf_fopen_files[i].bufferlen = 0;
pf_fopen_files[i].data = NULL;
}
if (!pf_fopen_files[i].data)
{
@ -1821,7 +1827,7 @@ void PF_fclose_i (int fnum)
COM_WriteFile(pf_fopen_files[fnum].name, pf_fopen_files[fnum].data, pf_fopen_files[fnum].len);
/*fall through*/
case FRIK_FILE_MMAP_READ:
/*cannot free accessible mem*/
pf_fopen_files[fnum].prinst->AddressableFree(pf_fopen_files[fnum].prinst, pf_fopen_files[fnum].data);
break;
case FRIK_FILE_READ:
@ -2907,13 +2913,21 @@ void QCBUILTIN PF_vtos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
}
void QCBUILTIN PF_forgetstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_strunzone(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
#ifdef QCGC
//gc frees everything for us.
#else
prinst->AddressableFree(prinst, prinst->stringtable + G_INT(OFS_PARM0));
#endif
}
void QCBUILTIN PF_dupstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //frik_file
void QCBUILTIN PF_strzone(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //frik_file
{
#ifdef QCGC
//just allocate a tempstring instead, because we can.
PF_strcat(prinst, pr_globals);
#else
char *buf;
int len = 0;
const char *s[8];
@ -2942,6 +2956,7 @@ void QCBUILTIN PF_dupstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
buf += l[i];
}
*buf = '\0';
#endif
}
//string(string str1, string str2) strcat
@ -4150,6 +4165,25 @@ void QCBUILTIN PF_bound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
G_FLOAT(OFS_RETURN) = G_FLOAT(OFS_PARM1);
}
void QCBUILTIN PF_mod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float a = G_FLOAT(OFS_PARM0);
float n = G_FLOAT(OFS_PARM1);
if (n == 0)
{
Con_Printf("mod by zero\n");
prinst->pr_trace = 1;
G_FLOAT(OFS_RETURN) = 0;
}
else
{
//because QC is inherantly floaty, lets use floats.
G_FLOAT(OFS_RETURN) = a - (n * (int)(a/n));
// G_FLOAT(OFS_RETURN) = a % n;
}
}
void QCBUILTIN PF_Sin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
@ -5253,12 +5287,19 @@ static void PR_AutoCvarApply(pubprogfuncs_t *prinst, eval_t *val, etype_t type,
val->_int = var->ival;
break;
case ev_string:
#ifdef QCGC
if (*var->string)
val->_int = PR_NewString(prinst, var->string);
else
val->_int = 0;
#else
if (val->_int)
prinst->RemoveProgsString(prinst, val->_int);
if (*var->string)
val->_int = PR_SetString(prinst, var->string);
else
val->_int = 0;
#endif
break;
case ev_vector:
{
@ -5350,7 +5391,7 @@ void PDECL PR_FoundDoTranslateGlobal(pubprogfuncs_t *progfuncs, char *name, eval
olds = PR_GetString(progfuncs, val->string);
news = PO_GetText(ctx, olds);
if (news != olds)
val->string = PR_NewString(progfuncs, news, 0);
val->string = PR_NewString(progfuncs, news);
}
//called after each progs is loaded
@ -5399,7 +5440,7 @@ lh_extension_t QSG_Extensions[] = {
//(which is why there are two lists of extensions here)
//note: not all of these are actually supported. This list mearly reflects the values of the PEXT_ constants.
//Check protocol.h to make sure that the related PEXT is enabled. The engine will only accept if they are actually supported.
{"FTE_PEXT_SETVIEW"}, //nq setview works.
{"FTE_PEXT_SETVIEW", 0, NULL, {NULL}, "NQ's svc_setview works correctly even in quakeworld"},
{"DP_ENT_SCALE"}, //entities may be rescaled
{"FTE_PEXT_LIGHTSTYLECOL"}, //lightstyles may have colours.
{"DP_ENT_ALPHA"}, //transparent entites
@ -5448,9 +5489,9 @@ lh_extension_t QSG_Extensions[] = {
// Tomaz - QuakeC File System End
{"BX_COLOREDTEXT"},
{"DP_CON_SET"},
{"DP_CON_SET", 0, NULL, {NULL}, "The 'set' console command exists, and can be used to create/set cvars."},
#ifndef SERVERONLY
{"DP_CON_SETA"}, //because the server doesn't write configs.
{"DP_CON_SETA", 0, NULL, {NULL}, "The 'seta' console command exists, like the 'set' command, but also marks the cvar for archiving, allowing it to be written into the user's config. Use this command in your default.cfg file."},
#endif
{"DP_EF_BLUE"}, //hah!! This is QuakeWorld!!!
{"DP_EF_FULLBRIGHT"}, //Rerouted to hexen2 support.
@ -5470,7 +5511,7 @@ lh_extension_t QSG_Extensions[] = {
{"DP_INPUTBUTTONS"},
{"DP_LITSUPPORT"},
{"DP_MD3_TAGSINFO", 2, NULL, {"gettagindex", "gettaginfo"}},
{"DP_MONSTERWALK"},
{"DP_MONSTERWALK", 0, NULL, {NULL}, "MOVETYPE_WALK is valid on non-player entities. Note that only players receive acceleration etc in line with none/bounce/fly/noclip movetypes on the player, thus you will have to provide your own accelerations (incluing gravity) yourself."},
{"DP_MOVETYPEBOUNCEMISSILE"}, //I added the code for hexen2 support.
{"DP_MOVETYPEFOLLOW"},
{"DP_QC_ASINACOSATANATAN2TAN", 5, NULL, {"asin", "acos", "atan", "atan2", "tan"}},
@ -5492,7 +5533,7 @@ lh_extension_t QSG_Extensions[] = {
{"DP_QC_GETSURFACE", 6, NULL, {"getsurfacenumpoints", "getsurfacepoint", "getsurfacenormal", "getsurfacetexture", "getsurfacenearpoint", "getsurfaceclippedpoint"}},
{"DP_QC_GETSURFACEPOINTATTRIBUTE", 1, NULL, {"getsurfacepointattribute"}},
{"DP_QC_MINMAXBOUND", 3, NULL, {"min", "max", "bound"}},
{"DP_QC_MULTIPLETEMPSTRINGS"},
{"DP_QC_MULTIPLETEMPSTRINGS", 0, NULL, {NULL}, "Superseded by DP_QC_UNLIMITEDTEMPSTRINGS. Functions that return a temporary string will not overwrite/destroy previous temporary strings until at least 16 strings are returned (or control returns to the engine)."},
{"DP_QC_RANDOMVEC", 1, NULL, {"randomvec"}},
{"DP_QC_RENDER_SCENE"}, //clear+addentity+setviewprop+renderscene+setmodel are available to menuqc.
{"DP_QC_SINCOSSQRTPOW", 4, NULL, {"sin", "cos", "sqrt", "pow"}},
@ -5507,7 +5548,7 @@ lh_extension_t QSG_Extensions[] = {
{"DP_QC_TRACE_MOVETYPE_HITMODEL"},
{"DP_QC_TRACE_MOVETYPE_WORLDONLY"},
{"DP_QC_TRACE_MOVETYPES"}, //this one is just a lame excuse to add annother extension...
{"DP_QC_UNLIMITEDTEMPSTRINGS"},
{"DP_QC_UNLIMITEDTEMPSTRINGS", 0, NULL, {NULL}, "Supersedes DP_QC_MULTIPLETEMPSTRINGS, superseded by FTE_QC_PERSISTENTTEMPSTRINGS. All temp strings will be valid at least until the QCVM returns."},
{"DP_QC_URI_ESCAPE", 2, NULL, {"uri_escape", "uri_unescape"}},
{"DP_QC_URI_GET", 1, NULL, {"uri_get"}},
{"DP_QC_URI_POST", 1, NULL, {"uri_get"}},
@ -5560,7 +5601,7 @@ lh_extension_t QSG_Extensions[] = {
{"FRIK_FILE", 11, NULL, {"stof", "fopen","fclose","fgets","fputs","strlen","strcat","substring","stov","strzone","strunzone"}},
{"FTE_CALLTIMEOFDAY", 1, NULL, {"calltimeofday"}},
{"FTE_CSQC_ALTCONSOLES_WIP", 4, NULL, {"con_getset", "con_printf", "con_draw", "con_input"}},
{"FTE_CSQC_BASEFRAME"}, //control for all skeletal models
{"FTE_CSQC_BASEFRAME", 0, NULL, {NULL}, "Specifies that .basebone, .baseframe, .baselerpfrac, etc exist. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations."},
{"FTE_CSQC_HALFLIFE_MODELS"}, //hl-specific skeletal model control
{"FTE_CSQC_SERVERBROWSER", 12, NULL, { "gethostcachevalue", "gethostcachestring", "resethostcachemasks", "sethostcachemaskstring", "sethostcachemasknumber",
"resorthostcache", "sethostcachesort", "refreshhostcache", "gethostcachenumber", "gethostcacheindexforkey",
@ -5568,21 +5609,21 @@ 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_CSQC_RENDERTARGETS_WIP", 0, NULL, {NULL}, "VF_DESTCOLOUR etc exist and are supported"},
{"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"}}, //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"}},
{"FTE_MEMALLOC", 4, NULL, {"memalloc", "memfree", "memcpy", "memfill8"}},
{"FTE_ISBACKBUFFERED", 1, NULL, {"isbackbuffered"}, "Allows you to check if a client has too many reliable messages pending."},
{"FTE_MEMALLOC", 4, NULL, {"memalloc", "memfree", "memcpy", "memfill8"}, "Allows dynamically allocating memory. Use pointers to access this memory. Memory will not be saved into saved games."},
#ifndef NOMEDIA
{"FTE_MEDIA_AVI"}, //playfilm supports avi files.
{"FTE_MEDIA_CIN"}, //playfilm command supports q2 cin files.
{"FTE_MEDIA_ROQ"}, //playfilm command supports q3 roq files
#endif
{"FTE_MULTIPROGS", 5, NULL, {"externcall", "addprogs", "externvalue", "externset", "instr"}}, //multiprogs functions are available.
{"FTE_MULTIPROGS", 5, NULL, {"externcall", "addprogs", "externvalue", "externset", "instr"}, "Multiple progs.dat files can be loaded inside the same qcvm."}, //multiprogs functions are available.
{"FTE_MULTITHREADED", 3, NULL, {"sleep", "fork", "abort"}},
#ifdef SERVER_DEMO_PLAYBACK
{"FTE_MVD_PLAYBACK"},
@ -5596,6 +5637,9 @@ lh_extension_t QSG_Extensions[] = {
{"FTE_QC_INTCONV", 4, NULL, {"stoi", "itos", "stoh", "htos"}},
{"FTE_QC_MATCHCLIENTNAME", 1, NULL, {"matchclientname"}},
{"FTE_QC_PAUSED"},
#ifdef QCGC
{"FTE_QC_PERSISTENTTEMPSTRINGS", 0, NULL, {NULL}, "Supersedes DP_QC_MULTIPLETEMPSTRINGS. Temp strings are garbage collected automatically, and do not expire while they're still in use. This makes strzone redundant."},
#endif
{"FTE_QC_RAGDOLL_WIP", 1, NULL, {"ragupdate", "skel_set_bone_world", "skel_mmap"}},
{"FTE_QC_SENDPACKET", 1, NULL, {"sendpacket"}}, //includes the SV_ParseConnectionlessPacket event.
{"FTE_QC_TRACETRIGGER"},

View File

@ -68,6 +68,7 @@ typedef struct lh_extension_s {
int numbuiltins;
qboolean *queried;
char *builtinnames[21]; //extend freely
char *description;
} lh_extension_t;
extern lh_extension_t QSG_Extensions[];
@ -114,6 +115,7 @@ void QCBUILTIN PF_Sin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Cos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Sqrt (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_bound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_mod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strlen(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strcat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_ftos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -124,8 +126,8 @@ void QCBUILTIN PF_stof (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_mod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_substring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_stov (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_dupstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_forgetstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strzone(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strunzone(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Spawn (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_checkbottom (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

View File

@ -142,6 +142,13 @@ void NPQTV_Sys_MainLoop(void);
#ifdef _WIN32
int StartLocalServer(int close);
#define HAVEAUTOUPDATE
int Sys_GetAutoUpdateSetting(void);
void Sys_SetAutoUpdateSetting(int newval);
#else
#define Sys_GetAutoUpdateSetting() -1
#define Sys_SetAutoUpdateSetting(n)
#endif
void Sys_Init (void);

View File

@ -260,13 +260,13 @@ static LRESULT WINAPI D3D9_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (!vid_initializing)
INS_TranslateKeyEvent (wParam, lParam, true, 0);
INS_TranslateKeyEvent (wParam, lParam, true, 0, false);
break;
case WM_KEYUP:
case WM_SYSKEYUP:
if (!vid_initializing)
INS_TranslateKeyEvent (wParam, lParam, false, 0);
INS_TranslateKeyEvent (wParam, lParam, false, 0, false);
break;
case WM_SYSCHAR:
@ -1064,6 +1064,7 @@ static void (D3D9_Draw_Init) (void)
static void (D3D9_Draw_Shutdown) (void)
{
R2D_Shutdown();
Image_Shutdown();
}
static void (D3D9_R_Init) (void)

View File

@ -398,13 +398,13 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
Cvar_ForceCallback(&v_gamma);
}
else if (!vid_initializing)
INS_TranslateKeyEvent (wParam, lParam, true, 0);
INS_TranslateKeyEvent (wParam, lParam, true, 0, false);
break;
case WM_KEYUP:
case WM_SYSKEYUP:
if (!vid_initializing)
INS_TranslateKeyEvent (wParam, lParam, false, 0);
INS_TranslateKeyEvent (wParam, lParam, false, 0, false);
break;
case WM_SYSCHAR:

View File

@ -25331,6 +25331,174 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\common\com_phys_bullet.cpp"
>
<FileConfiguration
Name="MinGLDebug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="MinGLDebug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="D3DDebug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="D3DDebug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="MinGLRelease|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="MinGLRelease|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="GLDebug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="GLDebug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Release Dedicated Server|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Release Dedicated Server|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="MRelease|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="MRelease|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug Dedicated Server|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug Dedicated Server|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="MDebug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="MDebug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="GLRelease|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="GLRelease|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="D3DRelease|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="D3DRelease|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\common\com_phys_ode.c"
>

View File

@ -1195,7 +1195,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
vec3_t lightdir;
int i;
vec3_t dist;
float add;
float add, m;
vec3_t shadelight, ambientlight;
if (e->light_known)
@ -1258,12 +1258,16 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
if (!r_vertexdlights.ival && r_dynamic.ival)
{
float *org = e->origin;
if (e->flags & RF_WEAPONMODEL)
org = r_refdef.vieworg;
//don't do world lights, although that might be funny
for (i=rtlights_first; i<RTL_FIRST; i++)
{
if (cl_dlights[i].radius)
{
VectorSubtract (e->origin,
VectorSubtract (org,
cl_dlights[i].origin,
dist);
add = cl_dlights[i].radius - Length(dist);
@ -1276,7 +1280,6 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
if (add > 0)
{
add*=5;
ambientlight[0] += add * cl_dlights[i].color[0];
ambientlight[1] += add * cl_dlights[i].color[1];
ambientlight[2] += add * cl_dlights[i].color[2];
@ -1289,12 +1292,19 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
}
}
for (i = 0; i < 3; i++) //clamp light so it doesn't get vulgar.
m = max(max(ambientlight[0], ambientlight[1]), ambientlight[2]);
if (m > 255)
{
if (ambientlight[i] > 128)
ambientlight[i] = 128;
if (shadelight[i] > 255)
shadelight[i] = 255;
ambientlight[0] *= 255.0/m;
ambientlight[1] *= 255.0/m;
ambientlight[2] *= 255.0/m;
}
m = max(max(shadelight[0], shadelight[1]), shadelight[2]);
if (m > 128)
{
shadelight[0] *= 128.0/m;
shadelight[1] *= 128.0/m;
shadelight[2] *= 128.0/m;
}
//MORE HUGE HACKS! WHEN WILL THEY CEASE!
@ -1356,25 +1366,24 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
ambientlight[0] = ambientlight[1] = ambientlight[2] = e->abslight;
}
//#define SHOWLIGHTDIR
{ //lightdir is absolute, shadevector is relative
if (e->flags & RF_WEAPONMODEL)
{
vec3_t temp;
temp[0] = DotProduct(lightdir, vpn);
temp[1] = -DotProduct(lightdir, vright);
temp[2] = DotProduct(lightdir, vup);
e->light_dir[0] = DotProduct(temp, e->axis[0]);
e->light_dir[1] = DotProduct(temp, e->axis[1]);
e->light_dir[2] = DotProduct(temp, e->axis[2]);
}
else
{
e->light_dir[0] = DotProduct(lightdir, e->axis[0]);
e->light_dir[1] = DotProduct(lightdir, e->axis[1]);
e->light_dir[2] = DotProduct(lightdir, e->axis[2]);
if (e->flags & RF_WEAPONMODEL)
{
vec3_t temp;
temp[0] = DotProduct(e->light_dir, vpn);
temp[1] = -DotProduct(e->light_dir, vright);
temp[2] = DotProduct(e->light_dir, vup);
VectorCopy(temp, e->light_dir);
}
VectorNormalize(e->light_dir);
}
VectorNormalize(e->light_dir);
shadelight[0] *= 1/255.0f;
shadelight[1] *= 1/255.0f;

View File

@ -112,8 +112,6 @@ void GLDraw_DeInit (void)
draw_disc = NULL;
GL_ShutdownPostProcessing();
Image_Shutdown();
#ifdef RTLIGHTS
Sh_Shutdown();
#endif

View File

@ -984,10 +984,14 @@ static texid_t Font_LoadHexen2Conchars(qboolean iso88591)
return r_nulltex;
}
qbyte default_conchar[/*11356*/] =
{
#include "lhfont.h"
};
static texid_t Font_LoadFallbackConchars(void)
{
texid_t tex;
extern qbyte default_conchar[11356];
int width, height;
unsigned int i;
qbyte *lump;

View File

@ -4726,7 +4726,7 @@ size_t Terr_GenerateBrushFace(vecV_t *points, size_t maxpoints, vec4_t *planes,
vec4_t verts2[128];
vec4_t *cverts;
int flip;
vec3_t d1, d2, n;
// vec3_t d1, d2, n;
size_t numverts;
//generate some huge quad/poly aligned with the plane

View File

@ -3089,6 +3089,8 @@ void Shader_Shutdown (void)
int i;
shader_t *shader;
Image_Shutdown();
if (!r_shaders)
return; /*nothing needs freeing yet*/
for (i = 0; i < r_numshaders; i++)
@ -5003,6 +5005,8 @@ static shader_t *R_LoadShader (const char *name, unsigned int usageflags, shader
Q_strncpyz(s->name, cleanname, sizeof(s->name));
s->usageflags = usageflags;
s->generator = defaultgen;
s->width = 0;
s->height = 0;
if (genargs)
s->genargs = strdup(genargs);
else

View File

@ -43,7 +43,6 @@ static texid_t shadowmap[2];
static int shadow_fbo_id;
static int shadow_fbo_depth_num;
static int crepuscular_fbo_id;
texid_t crepuscular_texture_id;
fbostate_t crepuscular_fbo;
shader_t *crepuscular_shader;
@ -103,11 +102,7 @@ void Sh_Reset(void)
R_DestroyTexture(crepuscular_texture_id);
crepuscular_texture_id = r_nulltex;
}
if (crepuscular_fbo_id)
{
qglDeleteFramebuffersEXT(1, &crepuscular_fbo_id);
crepuscular_fbo_id = 0;
}
GLBE_FBO_Destroy(&crepuscular_fbo);
#endif
}
void Sh_Shutdown(void)
@ -3145,6 +3140,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
#ifdef GLQUAKE
int oldfbo;
static mesh_t mesh;
image_t *oldsrccol;
static vecV_t xyz[4] =
{
{-1,-1,-1},
@ -3201,13 +3197,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
);
crepuscular_texture_id = Image_CreateTexture("***crepusculartexture***", NULL, 0);
qglGenTextures(1, &crepuscular_texture_id->num);
GL_MTBind(0, GL_TEXTURE_2D, crepuscular_texture_id);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth, vid.pixelheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
Image_Upload(crepuscular_texture_id, TF_RGBA32, NULL, NULL, vid.pixelwidth, vid.pixelheight, IF_LINEAR|IF_NOMIPMAP|IF_CLAMP|IF_NOGAMMA);
}
BE_Scissor(NULL);
@ -3219,12 +3209,16 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_BLEND);
GLBE_FBO_Pop(oldfbo);
Con_Printf("FIXME: shaderstate.tex_sourceocolour = crepuscular_texture_id\n");
oldsrccol = NULL;//shaderstate.tex_sourcecol;
GLBE_FBO_Sources(crepuscular_texture_id, NULL);
//shaderstate.tex_sourcecol = oldsrccol;
BE_SelectMode(BEM_STANDARD);
GLBE_DrawMesh_Single(crepuscular_shader, &mesh, NULL, &crepuscular_shader->defaulttextures, 0);
Con_Printf("FIXME: shaderstate.tex_sourceocolour = reset\n");
GLBE_FBO_Sources(oldsrccol, NULL);
#endif
}

View File

@ -96,7 +96,7 @@ extern cvar_t vid_wndalpha;
const char *wgl_extensions;
typedef enum {MS_WINDOWED, MS_FULLSCREEN, MS_FULLDIB, MS_UNINIT} modestate_t;
typedef enum {MS_WINDOWED, MS_FULLDIB, MS_FULLWINDOW, MS_UNINIT} modestate_t;
BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info);
@ -109,7 +109,6 @@ qboolean scr_skipupdate;
static DEVMODE gdevmode;
static qboolean vid_initialized = false;
static qboolean leavecurrentmode= true;
static qboolean vid_canalttab = false;
static qboolean vid_wassuspended = false;
extern qboolean mouseactive; // from in_win.c
@ -851,8 +850,11 @@ qboolean VID_SetFullDIBMode (rendererstate_t *info)
int wwidth, wheight;
RECT rect;
if (leavecurrentmode) //don't do this with d3d - d3d should set it's own video mode.
if (info->fullscreen != 2)
{ //make windows change res.
modestate = MS_FULLDIB;
gdevmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
if (info->bpp)
gdevmode.dmFields |= DM_BITSPERPEL;
@ -875,8 +877,11 @@ qboolean VID_SetFullDIBMode (rendererstate_t *info)
return false;
}
}
modestate = MS_FULLDIB;
else
{
modestate = MS_FULLWINDOW;
}
WindowRect.top = WindowRect.left = 0;
@ -915,7 +920,10 @@ qboolean VID_SetFullDIBMode (rendererstate_t *info)
SendMessage (dibwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon);
SendMessage (dibwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon);
ShowWindow (dibwindow, SW_SHOWDEFAULT);
if (modestate == MS_FULLWINDOW)
ShowWindow (dibwindow, SW_SHOWMAXIMIZED);
else
ShowWindow (dibwindow, SW_SHOWDEFAULT);
UpdateWindow (dibwindow);
// Because we have set the background brush for the window to NULL
@ -1958,7 +1966,7 @@ qboolean GLAppActivate(BOOL fActive, BOOL minimize)
if (fActive)
{
if (modestate != MS_WINDOWED)
if (modestate == MS_FULLDIB)
{
if (vid_canalttab && vid_wassuspended)
{
@ -1970,6 +1978,11 @@ qboolean GLAppActivate(BOOL fActive, BOOL minimize)
MoveWindow (mainwindow, 0, 0, gdevmode.dmPelsWidth, gdevmode.dmPelsHeight, false);
}
}
else if (modestate == MS_FULLWINDOW)
{
ShowWindow (mainwindow, SW_SHOWMAXIMIZED);
UpdateWindow (mainwindow);
}
gammapending = 0.5; //delayed gamma force
Cvar_ForceCallback(&v_gamma); //so the delay isn't so blatent when you have decent graphics drivers that don't break things.
@ -1977,7 +1990,7 @@ qboolean GLAppActivate(BOOL fActive, BOOL minimize)
if (!fActive)
{
if (modestate != MS_WINDOWED)
if (modestate == MS_FULLDIB)
{
if (vid_canalttab)
{
@ -2113,7 +2126,7 @@ LONG WINAPI GLMainWndProc (
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (!vid_initializing)
INS_TranslateKeyEvent(wParam, lParam, true, 0);
INS_TranslateKeyEvent(wParam, lParam, true, 0, false);
break;
// case WM_UNICHAR:
@ -2128,7 +2141,7 @@ LONG WINAPI GLMainWndProc (
case WM_KEYUP:
case WM_SYSKEYUP:
if (!vid_initializing)
INS_TranslateKeyEvent(wParam, lParam, false, 0);
INS_TranslateKeyEvent(wParam, lParam, false, 0, false);
break;
// this is complicated because Win32 seems to pack multiple mouse events into

View File

@ -290,7 +290,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"gl_Position = v_position;\n"
"gl_Position = vec4(v_position, 1.0);\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
@ -307,6 +307,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"vec2 textCoo = tc.st;\n"
"deltaTextCoord *= 1.0 / float(NUM_SAMPLES) * crep_density;\n"
"float illuminationDecay = 1.0;\n"
"gl_FragColor = vec4(0.0,0.0,0.0,0.0);\n"
"for(int i=0; i < NUM_SAMPLES ; i++)\n"
"{\n"
"textCoo -= deltaTextCoord;\n"
@ -1017,7 +1018,13 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"SamplerState SampleType;\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"return shaderTexture.Sample(SampleType, inp.tc) * inp.vcol;\n"
"float4 tex = shaderTexture.Sample(SampleType, inp.tc);\n"
"#ifdef MASK\n"
"if (tex.a < float(MASK))\n"
"discard;\n"
"#endif\n"
//FIXME: no fog, no colourmod
"return tex * inp.vcol;\n"
"}\n"
"#endif\n"
},

View File

@ -292,11 +292,11 @@ typedef struct shaderpass_s {
SHADER_PASS_NOCOLORARRAY = 1<<6,
//FIXME: remove these
SHADER_PASS_VIDEOMAP = 1 << 6,
SHADER_PASS_DETAIL = 1 << 7,
SHADER_PASS_LIGHTMAP = 1 << 8,
SHADER_PASS_DELUXMAP = 1 << 9,
SHADER_PASS_ANIMMAP = 1 << 10
SHADER_PASS_VIDEOMAP = 1 << 7,
SHADER_PASS_DETAIL = 1 << 8,
SHADER_PASS_LIGHTMAP = 1 << 9,
SHADER_PASS_DELUXMAP = 1 << 10,
SHADER_PASS_ANIMMAP = 1 << 11
} flags;
#ifdef D3D11QUAKE

View File

@ -1267,7 +1267,10 @@ void HTTP_CL_Think(void)
else if (dl->status != DL_ACTIVE)
dl->qdownload.percent = 0;
else if (dl->totalsize <= 0)
{
dl->qdownload.sizeunknown = true;
dl->qdownload.percent = 50;
}
else
dl->qdownload.percent = dl->completed*100.0f/dl->totalsize;
dl->qdownload.completedbytes = dl->completed;

View File

@ -616,7 +616,9 @@ reeval:
progfuncs->funcs.lastcalledbuiltinnumber = i;
if (i < externs->numglobalbuiltins)
{
#ifndef QCGC
prinst.numtempstringsstack = prinst.numtempstrings;
#endif
(*externs->globalbuiltins[i]) (&progfuncs->funcs, (struct globalvars_s *)current_progstate->globals);
if (prinst.continuestatement!=-1)
{
@ -810,7 +812,7 @@ reeval:
break;
}
pr_xstatement = st-pr_statements;
PR_RunError (&progfuncs->funcs, "bad pointer read in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name));
PR_RunError (&progfuncs->funcs, "bad pointer read in %s (from %#x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), i);
}
ptr = QCPOINTERM(i);
OPC->_int = ptr->_int;
@ -826,7 +828,7 @@ reeval:
break;
}
pr_xstatement = st-pr_statements;
PR_RunError (&progfuncs->funcs, "bad pointer read in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name));
PR_RunError (&progfuncs->funcs, "bad pointer read in %s (from %#x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), i);
}
ptr = QCPOINTERM(i);
OPC->_vector[0] = ptr->_vector[0];

View File

@ -705,7 +705,8 @@ eval_t *PDECL PR_FindGlobal(pubprogfuncs_t *ppf, const char *globname, progsnum_
return NULL;
}
void PDECL SetGlobalEdict(pubprogfuncs_t *ppf, struct edict_s *ed, int ofs)
//fixme: remove?
static void PDECL SetGlobalEdict(pubprogfuncs_t *ppf, struct edict_s *ed, int ofs)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
((int*)pr_globals)[ofs] = EDICT_TO_PROG(progfuncs, ed);
@ -831,31 +832,35 @@ string_t PDECL PR_StringToProgs (pubprogfuncs_t *ppf, const char *str)
prinst.allocedstrings[i] = (char*)str;
return (string_t)((unsigned int)i | STRING_STATIC);
}
if (prinst.numallocedstrings < prinst.maxallocedstrings)
{
i = prinst.numallocedstrings++;
prinst.allocedstrings[i] = (char*)str;
return (string_t)((unsigned int)i | STRING_STATIC);
}
prinst.maxallocedstrings += 1024;
ntable = progfuncs->funcs.parms->memalloc(sizeof(char*) * prinst.maxallocedstrings);
memcpy(ntable, prinst.allocedstrings, sizeof(char*) * prinst.numallocedstrings);
memset(ntable + prinst.numallocedstrings, 0, sizeof(char*) * (prinst.maxallocedstrings - prinst.numallocedstrings));
prinst.numallocedstrings = prinst.maxallocedstrings;
if (prinst.allocedstrings)
progfuncs->funcs.parms->memfree(prinst.allocedstrings);
prinst.allocedstrings = ntable;
for (i = prinst.numallocedstrings-1; i >= 0; i--)
{
if (!prinst.allocedstrings[i])
{
prinst.allocedstrings[i] = (char*)str;
return (string_t)((unsigned int)i | STRING_STATIC);
}
}
return 0;
i = prinst.numallocedstrings++;
prinst.allocedstrings[i] = (char*)str;
return (string_t)((unsigned int)i | STRING_STATIC);
}
//if ed is null, fld points to a global. if str_is_static, then s doesn't need its own memory allocated.
void PDECL PR_SetStringField(pubprogfuncs_t *progfuncs, struct edict_s *ed, string_t *fld, const char *str, pbool str_is_static)
{
#ifdef QCGC
*fld = PR_AllocTempString(progfuncs, str);
#else
if (!str_is_static)
str = PR_AddString(progfuncs, str, 0, false);
*fld = PR_StringToProgs(progfuncs, str);
#endif
}
char *PDECL PR_RemoveProgsString (pubprogfuncs_t *ppf, string_t str)
@ -870,7 +875,7 @@ char *PDECL PR_RemoveProgsString (pubprogfuncs_t *ppf, string_t str)
int i = str & ~STRING_SPECMASK;
if (i >= prinst.numallocedstrings)
{
progfuncs->funcs.pr_trace = 1;
PR_RunWarning(&progfuncs->funcs, "invalid static string %x\n", str);
return NULL;
}
if (prinst.allocedstrings[i])
@ -881,12 +886,11 @@ char *PDECL PR_RemoveProgsString (pubprogfuncs_t *ppf, string_t str)
}
else
{
progfuncs->funcs.pr_trace = 1;
PR_RunWarning(&progfuncs->funcs, "invalid static string %x (already free)\n", str);
return NULL; //urm, was freed...
}
}
printf("invalid static string %x\n", str);
progfuncs->funcs.pr_trace = 1;
PR_RunWarning(&progfuncs->funcs, "invalid static string %x\n", str);
return NULL;
}
@ -898,12 +902,8 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *ppf, string_t str)
int i = str & ~STRING_SPECMASK;
if (i >= prinst.numallocedstrings)
{
if (!progfuncs->funcs.pr_trace)
{
printf("invalid string %x\n", str);
progfuncs->funcs.pr_trace = 1;
PR_StackTrace(&progfuncs->funcs, false);
}
if (!progfuncs->funcs.pr_trace) //don't spam this
PR_RunWarning(&progfuncs->funcs, "invalid static string %x\n", str);
return "";
}
if (prinst.allocedstrings[i])
@ -911,25 +911,17 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *ppf, string_t str)
else
{
if (!progfuncs->funcs.pr_trace)
{
printf("invalid string %x\n", str);
progfuncs->funcs.pr_trace = 1;
PR_StackTrace(&progfuncs->funcs, false);
}
PR_RunWarning(&progfuncs->funcs, "invalid static string %x\n", str);
return ""; //urm, was freed...
}
}
if (((unsigned int)str & STRING_SPECMASK) == STRING_TEMP)
{
int i = str & ~STRING_SPECMASK;
if (i >= prinst.numtempstrings)
unsigned int i = str & ~STRING_SPECMASK;
if (i >= prinst.numtempstrings || !prinst.tempstrings[i])
{
if (!progfuncs->funcs.pr_trace)
{
printf("invalid temp string %x\n", str);
progfuncs->funcs.pr_trace = 1;
PR_StackTrace(&progfuncs->funcs, false);
}
PR_RunWarning(&progfuncs->funcs, "invalid temp string %x\n", str);
return "";
}
return prinst.tempstrings[i];
@ -938,19 +930,73 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *ppf, string_t str)
if ((unsigned int)str >= (unsigned int)prinst.addressableused)
{
if (!progfuncs->funcs.pr_trace)
{
printf("invalid string offset %x\n", str);
progfuncs->funcs.pr_trace = 1;
PR_StackTrace(&progfuncs->funcs, false);
}
PR_RunWarning(&progfuncs->funcs, "invalid string offset %x\n", str);
return "";
}
return progfuncs->funcs.stringtable + str;
}
string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str, unsigned int len)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
char **ntable;
int newmax;
int i;
if (!str)
return 0;
if (prinst.numtempstrings == prinst.maxtempstrings)
{
newmax = prinst.maxtempstrings + 1024;
ntable = progfuncs->funcs.parms->memalloc(sizeof(char*) * newmax);
memcpy(ntable, prinst.tempstrings, sizeof(char*) * prinst.numtempstrings);
#ifdef QCGC
memset(ntable+prinst.maxtempstrings, 0, sizeof(char*) * (newmax-prinst.numtempstrings));
#endif
prinst.maxtempstrings = newmax;
if (prinst.tempstrings)
progfuncs->funcs.parms->memfree(prinst.tempstrings);
prinst.tempstrings = ntable;
}
#ifdef QCGC
if (prinst.nexttempstring >= 0x10000000)
return 0;
do
{
i = prinst.nexttempstring++;
} while(prinst.tempstrings[i] != NULL);
if (i == prinst.numtempstrings)
prinst.numtempstrings++;
#else
i = prinst.numtempstrings;
if (i == 0x10000000)
return 0;
prinst.numtempstrings++;
#endif
prinst.tempstrings[i] = progfuncs->funcs.parms->memalloc(len);
*str = prinst.tempstrings[i];
return (string_t)((unsigned int)i | STRING_TEMP);
}
string_t PDECL PR_AllocTempString (pubprogfuncs_t *ppf, const char *str)
{
#ifdef QCGC
char *out;
string_t res;
size_t len;
if (!str)
return 0;
len = strlen(str)+1;
res = PR_AllocTempStringLen(ppf, &out, len);
memcpy(out, str, len);
return res;
#else
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
char **ntable;
int newmax;
@ -981,41 +1027,82 @@ string_t PDECL PR_AllocTempString (pubprogfuncs_t *ppf, const char *str)
strcpy(prinst.tempstrings[i], str);
return (string_t)((unsigned int)i | STRING_TEMP);
#endif
}
string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str, unsigned int len)
#ifdef QCGC
pbool PR_RunGC (progfuncs_t *progfuncs)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
char **ntable;
int newmax;
int i;
unsigned int p;
char *marked;
unsigned int *str;
// unsigned int r_l, r_d;
// unsigned long long starttime, markedtime, endtime;
if (!str)
return 0;
//only run the GC when we've itterated each string at least once.
if (prinst.nexttempstring < (prinst.maxtempstrings>>1) || prinst.nexttempstring < 200)
return false;
if (prinst.numtempstrings == prinst.maxtempstrings)
// starttime = Sys_GetClock();
marked = malloc(sizeof(*marked) * prinst.numtempstrings);
memset(marked, 0, sizeof(*marked) * prinst.numtempstrings);
//mark everything the qc has access to, even if it isn't even a string!
//note that I did try specifically checking only data explicitly marked as a string type, but that was:
//a) a smidge slower (lots of extra loops and conditions I guess)
//b) doesn't work with pointers/structs (yes, we assume it'll all be aligned).
//c) both methods got the same number of false positives in my test (2, probably dead strunzoned references)
for (str = (unsigned int*)prinst.addressablehunk, p = 0; p < prinst.addressableused; p+=sizeof(*str), str++)
{
newmax = prinst.maxtempstrings += 1024;
prinst.maxtempstrings += 1024;
ntable = progfuncs->funcs.parms->memalloc(sizeof(char*) * newmax);
memcpy(ntable, prinst.tempstrings, sizeof(char*) * prinst.numtempstrings);
prinst.maxtempstrings = newmax;
if (prinst.tempstrings)
progfuncs->funcs.parms->memfree(prinst.tempstrings);
prinst.tempstrings = ntable;
if ((*str & STRING_SPECMASK) == STRING_TEMP)
{
unsigned int idx = *str &~ STRING_SPECMASK;
if (idx < prinst.numtempstrings)
marked[idx] = true;
}
}
i = prinst.numtempstrings;
if (i == 0x10000000)
return 0;
//sweep
// markedtime = Sys_GetClock();
// r_l = 0;
// r_d = 0;
for (p = 0; p < prinst.numtempstrings; p++)
{
if (marked[p])
{
// r_l++;
}
else
break;
}
prinst.nexttempstring = p;
for (; p < prinst.numtempstrings; p++)
{
if (marked[p])
{
// r_l++;
}
else if (prinst.tempstrings[p])
{
// r_d++;
externs->memfree(prinst.tempstrings[p]);
prinst.tempstrings[p] = NULL;
}
}
prinst.numtempstrings++;
while (prinst.numtempstrings > 0 && prinst.tempstrings[prinst.numtempstrings-1] == NULL)
prinst.numtempstrings--;
prinst.tempstrings[i] = progfuncs->funcs.parms->memalloc(len);
*str = prinst.tempstrings[i];
free(marked);
return (string_t)((unsigned int)i | STRING_TEMP);
// endtime = Sys_GetClock();
// printf("live: %u, dead: %u, time: mark=%f, sweep=%f\n", r_l, r_d, (double)(markedtime - starttime) / Sys_GetClockRate(), (double)(endtime - markedtime) / Sys_GetClockRate());
return true;
}
#else
void PR_FreeTemps (progfuncs_t *progfuncs, int depth)
{
int i;
@ -1031,6 +1118,18 @@ void PR_FreeTemps (progfuncs_t *progfuncs, int depth)
prinst.numtempstrings = depth;
}
#endif
void PR_FreeAllTemps (progfuncs_t *progfuncs)
{
int i;
for (i = 0; i < prinst.numtempstrings; i++)
{
externs->memfree(prinst.tempstrings[i]);
prinst.tempstrings[i] = NULL;
}
prinst.numtempstrings = 0;
prinst.nexttempstring = 0;
}
pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf, pbool resetprofiles)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
@ -1120,9 +1219,6 @@ pubprogfuncs_t deffuncs = {
QC_EDICT_NUM,
QC_NUM_FOR_EDICT,
SetGlobalEdict,
PR_VarString,
NULL, //progstate
@ -1310,6 +1406,8 @@ static void PDECL PR_CloseProgs(pubprogfuncs_t *ppf)
free(inst->inst.addressablehunk);
#endif
PR_FreeAllTemps(inst);
if (inst->inst.allocedstrings)
f(inst->inst.allocedstrings);
inst->inst.allocedstrings = NULL;

View File

@ -389,6 +389,10 @@ enum qcop_e {
OP_SUB_PP,
OP_MOD_F,
OP_MOD_I,
OP_MOD_V,
OP_NUMOPS
};

View File

@ -525,9 +525,11 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool v
QC_snprintfz (line, sizeof(line), "union");
break;
case ev_string:
#ifndef QCGC
if (((unsigned int)val->string & STRING_SPECMASK) == STRING_TEMP)
return "<Stale Temporary String>";
else
#endif
QC_snprintfz (line, sizeof(line), "%s", PR_StringToNative(&progfuncs->funcs, val->string));
break;
case ev_entity:
@ -602,8 +604,11 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool v
// sprintf(line, "ent%i.%s", entnum, fielddef->s_name);
}
break;
case ev_accessor:
QC_snprintfz (line, sizeof(line), "(accessor)", type);
break;
default:
QC_snprintfz (line, sizeof(line), "bad type %i", type);
QC_snprintfz (line, sizeof(line), "(bad type %i)", type);
break;
}
@ -646,9 +651,11 @@ char *PDECL PR_UglyValueString (pubprogfuncs_t *ppf, etype_t type, eval_t *val)
char *outs = line;
int outb = sizeof(line)-2;
const char *ins;
#ifndef QCGC
if (((unsigned int)val->string & STRING_SPECMASK) == STRING_TEMP)
return "<Stale Temporary String>";
else
#endif
ins = PR_StringToNative(&progfuncs->funcs, val->string);
//markup the output string.
while(*ins && outb > 0)
@ -721,7 +728,7 @@ char *PDECL PR_UglyValueString (pubprogfuncs_t *ppf, etype_t type, eval_t *val)
if (val->_vector[0] == (int)val->_vector[0] && val->_vector[1] == (int)val->_vector[1] && val->_vector[2] == (int)val->_vector[2])
sprintf (line, "%i %i %i", (int)val->_vector[0], (int)val->_vector[1], (int)val->_vector[2]);
else
sprintf (line, "%f %f %f", val->_vector[0], val->_vector[1], val->_vector[2]);
sprintf (line, "%g %g %g", val->_vector[0], val->_vector[1], val->_vector[2]);
break;
case ev_pointer:
QC_snprintfz (line, sizeof(line), "%#x", val->_int);
@ -1125,7 +1132,11 @@ pbool PDECL ED_ParseEval (pubprogfuncs_t *ppf, eval_t *eval, int type, const cha
switch (type & ~DEF_SAVEGLOBAL)
{
case ev_string:
#ifdef QCGC
st = PR_AllocTempString(&progfuncs->funcs, s);
#else
st = PR_StringToProgs(&progfuncs->funcs, ED_NewString (&progfuncs->funcs, s, 0, true));
#endif
eval->string = st;
break;
@ -1209,7 +1220,11 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, int qcptr, unsigned int fldofs, int
switch (type)
{
case ev_string:
#ifdef QCGC
st = PR_AllocTempString(&progfuncs->funcs, s);
#else
st = PR_StringToProgs(&progfuncs->funcs, ED_NewString (&progfuncs->funcs, s, 0, true));
#endif
*(string_t *)(progfuncs->funcs.stringtable + qcptr) = st;
break;

View File

@ -222,21 +222,6 @@ void PDECL PR_GenerateStatementString (pubprogfuncs_t *ppf, int statementnum, ch
PR_StackTrace
============
*/
char *QC_ucase(char *str)
{
static char s[1024];
strcpy(s, str);
str = s;
while(*str)
{
if (*str >= 'a' && *str <= 'z')
*str = *str - 'a' + 'A';
str++;
}
return s;
}
static void PDECL PR_PrintRelevantLocals(progfuncs_t *progfuncs)
{
//scan for op_address/op_load instructions within the function
@ -382,46 +367,6 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf, int showlocals)
}
}
/*
============
PR_Profile_f
============
*/
/*
void PR_Profile_f (void)
{
dfunction_t *f, *best;
int max;
int num;
unsigned int i;
num = 0;
do
{
max = 0;
best = NULL;
for (i=0 ; i<pr_progs->numfunctions ; i++)
{
f = &pr_functions[i];
if (f->profile > max && f->first_statement >=0)
{
max = f->profile;
best = f;
}
}
if (best)
{
if (num < 10)
printf ("%7i %s\n", best->profile, best->s_name);
num++;
best->profile = 0;
}
} while (best);
}
*/
/*
============
PR_RunError
@ -873,7 +818,11 @@ char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key)
switch (type&~DEF_SAVEGLOBAL)
{
case ev_string:
#ifdef QCGC
*(string_t *)val = PR_AllocTempString(&progfuncs->funcs, assignment);
#else
*(string_t *)val = PR_StringToProgs(&progfuncs->funcs, ED_NewString (&progfuncs->funcs, assignment, 0, true));
#endif
break;
case ev_float:
@ -1464,7 +1413,9 @@ void PDECL PR_ExecuteProgram (pubprogfuncs_t *ppf, func_t fnum)
int s;
#ifndef QCGC
int tempdepth;
#endif
unsigned int newprogs = (fnum & 0xff000000)>>24;
@ -1530,14 +1481,21 @@ void PDECL PR_ExecuteProgram (pubprogfuncs_t *ppf, func_t fnum)
s = PR_EnterFunction (progfuncs, f, initial_progs);
#ifndef QCGC
tempdepth = prinst.numtempstringsstack;
#endif
PR_ExecuteCode(progfuncs, s);
PR_SwitchProgsParms(progfuncs, initial_progs);
#ifndef QCGC
PR_FreeTemps(progfuncs, tempdepth);
prinst.numtempstringsstack = tempdepth;
#else
if (!oldexitdepth)
PR_RunGC(progfuncs);
#endif
prinst.exitdepth = oldexitdepth;
}
@ -1641,7 +1599,9 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
int oldexitdepth;
int s;
#ifndef QCGC
int tempdepth;
#endif
progsnum_t prnum = thread->xprogs;
int fnum = thread->xfunction;
@ -1713,13 +1673,17 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
pr_xfunction = f;
s = thread->xstatement;
#ifndef QCGC
tempdepth = prinst.numtempstringsstack;
#endif
PR_ExecuteCode(progfuncs, s);
PR_SwitchProgsParms(progfuncs, initial_progs);
#ifndef QCGC
PR_FreeTemps(progfuncs, tempdepth);
prinst.numtempstringsstack = tempdepth;
#endif
prinst.exitdepth = oldexitdepth;
pr_xfunction = oldf;

View File

@ -70,9 +70,13 @@ typedef struct
typedef struct prinst_s
{
char **tempstrings;
int maxtempstrings;
int numtempstrings;
int numtempstringsstack;
unsigned int maxtempstrings;
unsigned int numtempstrings;
#ifdef QCGC
unsigned int nexttempstring;
#else
unsigned int numtempstringsstack;
#endif
char **allocedstrings;
int maxallocedstrings;
@ -294,10 +298,10 @@ extern int noextensions;
typedef enum
{
PST_DEFAULT, //16
PST_FTE32, //32
PST_KKQWSV, //24
PST_QTEST,
PST_DEFAULT,//everything 16bit
PST_FTE32, //everything 32bit
PST_KKQWSV, //32bit statements, 16bit globaldefs. NO SAVED GAMES.
PST_QTEST, //16bit statements, 32bit globaldefs(differences converted on load)
} progstructtype_t;
#ifndef COMPILER
@ -351,10 +355,10 @@ typedef struct extensionbuiltin_s {
#define pr_progs current_progstate->progs
#define pr_cp_functions current_progstate->functions
#define pr_strings current_progstate->strings
#define pr_globaldefs16 ((ddef16_t*)current_progstate->globaldefs)
#define pr_globaldefs32 ((ddef32_t*)current_progstate->globaldefs)
#define pr_fielddefs16 ((ddef16_t*)current_progstate->fielddefs)
#define pr_fielddefs32 ((ddef32_t*)current_progstate->fielddefs)
#define pr_globaldefs16 ((ddef16_t*)current_progstate->globaldefs16)
#define pr_globaldefs32 ((ddef32_t*)current_progstate->globaldefs32)
#define pr_fielddefs16 ((ddef16_t*)current_progstate->fielddefs16)
#define pr_fielddefs32 ((ddef32_t*)current_progstate->fielddefs32)
#define pr_statements16 ((dstatement16_t*)current_progstate->statements)
#define pr_statements32 ((dstatement32_t*)current_progstate->statements)
//#define pr_global_struct current_progstate->global_struct
@ -368,6 +372,8 @@ typedef struct extensionbuiltin_s {
void PR_Init (void);
pbool PR_RunWarning (pubprogfuncs_t *progfuncs, char *error, ...);
void PDECL PR_ExecuteProgram (pubprogfuncs_t *progfuncs, func_t fnum);
int PDECL PR_LoadProgs(pubprogfuncs_t *progfncs, const char *s, builtin_t *builtins, int numbuiltins);
int PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstate_t *progstate, pbool complain);
@ -379,6 +385,8 @@ void PR_Profile_f (void);
struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *progfuncs);
void PDECL ED_Free (pubprogfuncs_t *progfuncs, struct edict_s *ed);
pbool PR_RunGC (progfuncs_t *progfuncs);
string_t PDECL PR_AllocTempString (pubprogfuncs_t *ppf, const char *str);
char *PDECL ED_NewString (pubprogfuncs_t *ppf, const char *string, int minlength, pbool demarkup);
// returns a copy of the string allocated from the server's string heap

View File

@ -34,6 +34,9 @@
#define ASMCALL PDECL
#endif
#define QCGC
struct edict_s;
struct entvars_s;
struct globalvars_s;
@ -84,8 +87,6 @@ struct pubprogfuncs_s
struct edict_s *(PDECL *EDICT_NUM) (pubprogfuncs_t *prinst, unsigned int n); //get the nth edict
unsigned int (PDECL *NUM_FOR_EDICT) (pubprogfuncs_t *prinst, struct edict_s *e); //so you can find out what that 'n' will be
void (PDECL *SetGlobalEdict) (pubprogfuncs_t *prinst, struct edict_s *ed, int ofs); //set a global to an edict (partially obsolete)
char *(PDECL *VarString) (pubprogfuncs_t *prinst, int first); //returns a string made up of multiple arguments
struct progstate_s **progstate; //internal to the library.
@ -308,9 +309,14 @@ typedef union eval_s
#define PR_SetStringOfs(p,o,s) (G_INT(o) = s - p->stringtable)
*/
//#define PR_SetString(p, s) ((s&&*s)?(s - p->stringtable):0)
#define PR_NewString(p, s, l) PR_SetString(p, PR_AddString(p, s, l, false))
/**/
#ifdef QCGC
#define PR_NewString(p, s) (p)->TempString(p, s)
#else
#define PR_NewString(p, s) PR_SetString(p, PR_AddString(p, s, 0, false))
#endif
#define ev_prog ev_integer
#define E_STRING(o) (char *)(((int *)((char *)ed) + progparms.edictsize)[o])

View File

@ -308,7 +308,7 @@ struct accessor_s
struct QCC_type_s *type;
struct QCC_type_s *indexertype; //null if not indexer
struct QCC_def_s *getset_func[2];
pbool *getset_isref[2];
pbool getset_isref[2];
char *fieldname;
};
@ -376,6 +376,7 @@ typedef struct QCC_def_s
pbool subscoped_away:1;
pbool followptr:1;
pbool strip:1;
pbool allowinline:1;
temp_t *temp;
} QCC_def_t;
@ -587,6 +588,7 @@ extern int optres_compound_jumps;
extern int optres_stripfunctions;
extern int optres_locals_overlapping;
extern int optres_logicops;
extern int optres_inlines;
pbool CompileParams(progfuncs_t *progfuncs, int doall, int nump, char **parms);
@ -851,6 +853,7 @@ void QCC_PR_NewLine (pbool incomment);
#define GDF_CONST 4
#define GDF_STRIP 8 //always stripped, regardless of optimisations. used for class member fields
#define GDF_SILENT 16 //used by the gui, to suppress ALL warnings.
#define GDF_INLINE 32 //attempt to inline calls to this function
QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool allocate, int arraysize, unsigned int flags);
char *QCC_PR_CheckCompConstTooltip(char *word, char *outstart, char *outend);

View File

@ -276,11 +276,25 @@ skipwhite:
qcc_token[len] = 0;
return (char*)data;
}
else if (c=='\0') //\n does not terminate the string. that would break compatibility with vanilla saved games
else if (c=='\0')
{
printf("ERROR: Unterminated string\n");
qcc_token[len] = 0;
return (char*)data;
}
else if (c=='\n' || c=='\r')
{ //new lines are awkward.
//vanilla saved games do not add \ns on load
//terminating the string on a new line thus has compatbility issues.
//while "wad" "c:\foo\" does happen in the TF community (fucked tools)
//so \r\n terminates the string if the last char was an escaped quote, but not otherwise.
if (len > 0 && qcc_token[len-1] == '\"')
{
printf("ERROR: new line in string\n");
qcc_token[len] = 0;
return (char*)data;
}
}
if (len >= sizeof(qcc_token)-1)
;
else

View File

@ -131,6 +131,7 @@ int optres_compound_jumps;
int optres_stripfunctions;
int optres_locals_overlapping;
int optres_logicops;
int optres_inlines;
int optres_test1;
int optres_test2;
@ -383,14 +384,14 @@ QCC_opcode_t pr_opcodes[] =
//Later are additions by DMW.
{7, "<CALL1H>", "CALL1H", -1, ASSOC_LEFT, &type_function, &type_vector, &type_void},
{7, "<CALL2H>", "CALL2H", -1, ASSOC_LEFT, &type_function, &type_vector, &type_vector},
{7, "<CALL3H>", "CALL3H", -1, ASSOC_LEFT, &type_function, &type_vector, &type_vector},
{7, "<CALL4H>", "CALL4H", -1, ASSOC_LEFT, &type_function, &type_vector, &type_vector},
{7, "<CALL5H>", "CALL5H", -1, ASSOC_LEFT, &type_function, &type_vector, &type_vector},
{7, "<CALL6H>", "CALL6H", -1, ASSOC_LEFT, &type_function, &type_vector, &type_vector},
{7, "<CALL7H>", "CALL7H", -1, ASSOC_LEFT, &type_function, &type_vector, &type_vector},
{7, "<CALL8H>", "CALL8H", -1, ASSOC_LEFT, &type_function, &type_vector, &type_vector},
{7, "<CALL1H>", "CALL1H", -1, ASSOC_RIGHT, &type_function, &type_vector, &type_void},
{7, "<CALL2H>", "CALL2H", -1, ASSOC_RIGHT, &type_function, &type_vector, &type_vector},
{7, "<CALL3H>", "CALL3H", -1, ASSOC_RIGHT, &type_function, &type_vector, &type_vector},
{7, "<CALL4H>", "CALL4H", -1, ASSOC_RIGHT, &type_function, &type_vector, &type_vector},
{7, "<CALL5H>", "CALL5H", -1, ASSOC_RIGHT, &type_function, &type_vector, &type_vector},
{7, "<CALL6H>", "CALL6H", -1, ASSOC_RIGHT, &type_function, &type_vector, &type_vector},
{7, "<CALL7H>", "CALL7H", -1, ASSOC_RIGHT, &type_function, &type_vector, &type_vector},
{7, "<CALL8H>", "CALL8H", -1, ASSOC_RIGHT, &type_function, &type_vector, &type_vector},
{7, "=", "STORE_I", 6, ASSOC_RIGHT, &type_integer, &type_integer, &type_integer},
{7, "=", "STORE_IF", 6, ASSOC_RIGHT, &type_float, &type_integer, &type_integer},
@ -606,6 +607,10 @@ QCC_opcode_t pr_opcodes[] =
{7, "-", "SUB_PI", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer},
{7, "-", "SUB_PP", 6, ASSOC_LEFT, &type_pointer, &type_pointer, &type_integer},
{7, "%", "MOD_F", 6, ASSOC_LEFT, &type_float, &type_float, &type_float},
{7, "%", "MOD_I", 6, ASSOC_LEFT, &type_integer, &type_integer, &type_integer},
{7, "%", "MOD_V", 6, ASSOC_LEFT, &type_vector, &type_vector, &type_vector},
{0, NULL}
};
@ -857,6 +862,10 @@ QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] =
&pr_opcodes[OP_RSHIFT_I],
&pr_opcodes[OP_LSHIFT_I],
&pr_opcodes[OP_MOD_F],
&pr_opcodes[OP_MOD_I],
&pr_opcodes[OP_MOD_V],
NULL
}, { //4
@ -1951,6 +1960,15 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
return nd;
}
break;
case OP_XOR_I:
optres_constantarithmatic++;
return QCC_MakeIntConst(G_INT(var_a->ofs) ^ G_INT(var_b->ofs));
case OP_RSHIFT_I:
optres_constantarithmatic++;
return QCC_MakeIntConst(G_INT(var_a->ofs) >> G_INT(var_b->ofs));
case OP_LSHIFT_I:
optres_constantarithmatic++;
return QCC_MakeIntConst(G_INT(var_a->ofs) << G_INT(var_b->ofs));
case OP_BITOR_F:
optres_constantarithmatic++;
return QCC_MakeFloatConst((float)((int)G_FLOAT(var_a->ofs) | (int)G_FLOAT(var_b->ofs)));
@ -2001,6 +2019,20 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
optres_constantarithmatic++;
return QCC_MakeIntConst(G_INT(var_a->ofs) - G_INT(var_b->ofs));
case OP_MOD_I:
if (!G_INT(var_b->ofs))
break;
optres_constantarithmatic++;
return QCC_MakeIntConst(G_INT(var_a->ofs) % G_INT(var_b->ofs));
case OP_MOD_F:
{
float a = G_FLOAT(var_a->ofs),n=G_FLOAT(var_b->ofs);
if (!n)
break;
optres_constantarithmatic++;
return QCC_MakeFloatConst(a - (n * (int)(a/n)));
}
case OP_ADD_IF:
optres_constantarithmatic++;
return QCC_MakeFloatConst(G_INT(var_a->ofs) + G_FLOAT(var_b->ofs));
@ -2233,7 +2265,7 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
case OP_STORE_I:
case OP_STORE_ENT:
case OP_STORE_FNC:
if (var_a->constant && var_a->type->type == ev_integer && !G_INT(var_a->ofs))
if (var_a && var_a->constant && var_a->type->type == ev_integer && !G_INT(var_a->ofs))
{
//you're allowed to assign 0i to anything
if (op - pr_opcodes == OP_STORE_V) //make sure vectors get set properly.
@ -2264,7 +2296,7 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
case OP_STOREP_I:
case OP_STOREP_ENT:
case OP_STOREP_FNC:
if (var_a->constant && var_a->type->type == ev_integer && !G_INT(var_a->ofs))
if (var_a && var_a->constant && var_a->type->type == ev_integer && !G_INT(var_a->ofs))
{
//you're allowed to assign 0i to anything
if (op - pr_opcodes == OP_STOREP_V) //make sure vectors get set properly.
@ -2297,15 +2329,15 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
case OP_LOADA_I:
break;
case OP_AND_F:
if (var_a->ofs == var_b->ofs)
if (var_a && var_b && (var_a->ofs == var_b->ofs))
QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Parameter offsets for && are the same");
if (var_a->constant || var_b->constant)
if (var_a && var_b && (var_a->constant || var_b->constant))
QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Result of comparison is constant");
break;
case OP_OR_F:
if (var_a->ofs == var_b->ofs)
if (var_a && var_b && (var_a->ofs == var_b->ofs))
QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Parameters for || are the same");
if (var_a->constant || var_b->constant)
if (var_a && var_b && (var_a->constant || var_b->constant))
QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Result of comparison is constant");
break;
case OP_EQ_F:
@ -2551,6 +2583,55 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
return var_c;
}
break;
case OP_MOD_I:
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_integer, type_integer};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "ModInt", NULL, false, 0, 0);
if (!fnc)
QCC_PR_ParseError(0, "ModInt function not defined: cannot emulate int%%int");
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_integer;
return var_c;
}
break;
case OP_MOD_F:
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_float, type_float};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "mod", NULL, false, 0, 0);
if (!fnc)
{
//a - (n * floor(a/n));
//(except using v|v instead of floor)
numstatements--;
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_DIV_F], var_a, var_b, NULL, STFL_CONVERTA|STFL_CONVERTB|STFL_PRESERVEA|STFL_PRESERVEB);
var_c = QCC_PR_Statement(&pr_opcodes[OP_BITOR_F], var_c, var_c, NULL);
var_c = QCC_PR_Statement(&pr_opcodes[OP_MUL_F], var_b, var_c, NULL);
return QCC_PR_Statement(&pr_opcodes[OP_SUB_F], var_a, var_c, NULL);
// QCC_PR_ParseError(0, "mod function not defined: cannot emulate float%%float");
}
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_float;
return var_c;
}
break;
case OP_MOD_V:
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_vector, type_vector};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "ModVec", NULL, false, 0, 0);
if (!fnc)
QCC_PR_ParseError(0, "ModVec function not defined: cannot emulate vector%%vector");
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_vector;
return var_c;
}
break;
case OP_SUB_I:
{
QCC_def_t *arg[2] = {var_a, var_b};
@ -3202,7 +3283,17 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
return QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_FV], var_a, var_b, NULL, flags&STFL_PRESERVEB);
default:
QCC_PR_ParseError(ERR_BADEXTENSION, "Opcode \"%s|%s\" not valid for target. Consider the use of: #pragma target fte\n", op->name, op->opname);
{
int oldtarg = qcc_targetformat;
pbool shamelessadvertising;
qcc_targetformat = QCF_FTE;
shamelessadvertising = QCC_OPCodeValid(op);
qcc_targetformat = oldtarg;
if (shamelessadvertising)
QCC_PR_ParseError(ERR_BADEXTENSION, "Opcode \"%s|%s\" not valid for target. Consider the use of: #pragma target fte\n", op->name, op->opname);
else
QCC_PR_ParseError(ERR_BADEXTENSION, "Opcode \"%s|%s\" is not supported.\n", op->name, op->opname);
}
break;
}
}
@ -3668,6 +3759,307 @@ void QCC_PrecacheFileOptimised (char *n, int ch)
numfiles++;
}
struct inlinectx_s
{
QCC_def_t *fdef;
QCC_dfunction_t *func;
QCC_def_t **arglist;
QCC_def_t *result;
struct
{
QCC_def_t *def;
int srcofs;
} locals[64];
int numlocals;
};
pbool QCC_PR_InlinePushResult(struct inlinectx_s *ctx, int ofs, QCC_def_t *def)
{
int i;
for (i = 0; i < ctx->numlocals; i++)
{
if (ctx->locals[i].srcofs == ofs)
break;
}
if (i == ctx->numlocals)
{
if (ctx->numlocals >= sizeof(ctx->locals)/sizeof(ctx->locals[0]))
return false;
ctx->locals[i].srcofs = ofs;
ctx->numlocals++;
}
ctx->locals[i].def = def;
return true;
}
//FIXME: too expensive. store a reference to the defs in the statements instead
QCC_def_t *QCC_PR_InlineFindDef(struct inlinectx_s *ctx, int ofs)
{
QCC_def_t *d;
int p;
int pstart = ctx->func->parm_start;
for (p = 0; p < ctx->numlocals; p++)
{
if (ctx->locals[p].srcofs == ofs)
{
d = ctx->locals[p].def;
ctx->locals[p].def = NULL;
return d;
}
}
if (ofs < RESERVED_OFS)
{
if (ofs == OFS_RETURN)
{
def_ret.type = type_void;
return &def_ret;
}
ofs -= OFS_PARM0;
ofs /= 3;
def_parms[ofs].type = type_void;
return &def_parms[ofs];
}
if (ofs < pstart || ofs >= pstart+ctx->func->locals)
{
for (d = &pr.def_head; d; d = d->next)
{
if (d->ofs == ofs)
return d;
}
return NULL; //not found?
}
for (p = 0; p < ctx->func->numparms; pstart += ctx->func->parm_size[p++])
{
if (ofs < pstart+ctx->func->parm_size[p])
return ctx->arglist[p];
}
if (ctx->numlocals >= sizeof(ctx->locals)/sizeof(ctx->locals[0]))
return NULL;
ctx->locals[ctx->numlocals].srcofs = ofs;
ctx->locals[ctx->numlocals].def = QCC_GetTemp(type_float);
return ctx->locals[ctx->numlocals++].def;
}
//returns a string saying why inlining failed.
static char *QCC_PR_InlineStatements(struct inlinectx_s *ctx)
{
QCC_def_t *a, *b, *c;
QCC_statement_t *st;
// float af,bf;
// int i;
st = &statements[ctx->func->first_statement];
while(1)
{
switch(st->op)
{
case OP_IF_F:
case OP_IFNOT_F:
case OP_IF_I:
case OP_IFNOT_I:
case OP_IF_S:
case OP_IFNOT_S:
case OP_GOTO:
case OP_SWITCH_F:
case OP_SWITCH_I:
case OP_SWITCH_E:
case OP_SWITCH_FNC:
case OP_SWITCH_S:
case OP_SWITCH_V:
return "function contains branches"; //conditionals are not supported in any way. this keeps the code linear. each input can only come from a single place.
/* case OP_CALL0:
case OP_CALL1:
case OP_CALL2:
case OP_CALL3:
case OP_CALL4:
case OP_CALL5:
case OP_CALL6:
case OP_CALL7:
case OP_CALL8:
case OP_CALL1H:
case OP_CALL2H:
case OP_CALL3H:
case OP_CALL4H:
case OP_CALL5H:
case OP_CALL6H:
case OP_CALL7H:
case OP_CALL8H:
return "function contains function calls"; //conditionals are not supported in any way. this keeps the code linear. each input can only come from a single place.
*/
case OP_RETURN:
case OP_DONE:
a = QCC_PR_InlineFindDef(ctx, st->a);
ctx->result = a;
if (!a)
return "OP_RETURN no a";
return NULL;
case OP_BOUNDCHECK:
a = QCC_PR_InlineFindDef(ctx, st->a);
QCC_PR_InlinePushResult(ctx, st->a, a);
if (a->constant)
{
int i = G_INT(a->ofs);
if (i < st->c || i >= st->b)
QCC_PR_ParseWarning(0, "constant value exceeds bounds failed bounds check while inlining\n");
}
else
QCC_PR_SimpleStatement(OP_BOUNDCHECK, a->ofs, st->b, st->c, false);
break;
default:
if ((st->op >= OP_CALL0 && st->op <= OP_CALL8) || (st->op >= OP_CALL1H && st->op <= OP_CALL8H))
{
//function calls are a little weird in that they have no outputs
QCC_statement_t *nst;
if (st->a)
{
a = QCC_PR_InlineFindDef(ctx, st->a);
if (!a)
return "unable to determine what a was";
}
else
a = NULL;
c = QCC_PR_StatementFlags(&pr_opcodes[st->op], a, NULL, &nst, 0);
if (st->b)
{
b = QCC_PR_InlineFindDef(ctx, st->b);
if (!b)
return "unable to determine what a was";
QCC_FreeTemp(b);
nst->b = b->ofs;
}
if (st->c)
{
c = QCC_PR_InlineFindDef(ctx, st->c);
if (!c)
return "unable to determine what a was";
QCC_FreeTemp(c);
nst->c = c->ofs;
}
}
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT)
{
//a->b
if (st->a)
{
a = QCC_PR_InlineFindDef(ctx, st->a);
if (!a)
return "unable to determine what a was";
}
else
a = NULL;
b = QCC_PR_InlineFindDef(ctx, st->b);
c = QCC_PR_StatementFlags(&pr_opcodes[st->op], a, b, NULL, 0);
if (!QCC_PR_InlinePushResult(ctx, st->b, c))
return "too many temps";
}
else
{
//a+b->c
if (st->a)
{
a = QCC_PR_InlineFindDef(ctx, st->a);
if (!a)
return "unable to determine what a was";
}
else
a = NULL;
if (st->b)
{
b = QCC_PR_InlineFindDef(ctx, st->b);
if (!b)
return "unable to determine what b was";
}
else
b = NULL;
if (pr_opcodes[st->op].associative == ASSOC_LEFT && pr_opcodes[st->op].type_c != &type_void)
{
QCC_def_t *r;
c = QCC_PR_InlineFindDef(ctx, st->c);
r = QCC_PR_StatementFlags(&pr_opcodes[st->op], a, b, NULL, 0);
if (c)
c = QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_ENT], r, c, NULL, 0);
else
c = r;
if (!QCC_PR_InlinePushResult(ctx, st->c, c))
return "too many temps";
}
else
{
if (st->c)
{
c = QCC_PR_InlineFindDef(ctx, st->c);
if (!c)
return "unable to determine what c was";
}
else
c = NULL;
QCC_PR_SimpleStatement(st->op, a?a->ofs:0, b?b->ofs:0, c?c->ofs:0, false);
}
}
break;
}
st++;
}
}
QCC_def_t *QCC_PR_Inline(QCC_def_t *fdef, QCC_def_t *arglist[])
{
QCC_def_t *dd = NULL;
struct inlinectx_s ctx;
char *error;
int statements;
//make sure that its a function type and that there's no special weirdness
if (fdef->type->type != ev_function || fdef->type->num_parms > 8 || fdef->type->vargs || fdef->type->vargcount)
return NULL;
ctx.numlocals = 0;
ctx.arglist = arglist;
ctx.fdef = fdef;
ctx.result = NULL;
ctx.func = &functions[G_INT(fdef->ofs)];
if ((int)ctx.func->first_statement <= 0)
return NULL; //don't try to inline builtins. that simply cannot work.
if (!strcmp(fdef->name, "loadalltables"))
printf("debug: %s\n", fdef->name);
statements = numstatements;
error = QCC_PR_InlineStatements(&ctx);
if (error)
{
QCC_PR_ParseWarning(0, "Couldn't inline \"%s\": %s", fdef->name, error);
QCC_PR_ParsePrintDef(0, fdef);
}
if (ctx.result)
{
dd = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (dd, 0, sizeof(QCC_def_t));
dd->type = fdef->type->aux_type;
dd->ofs = ctx.result->ofs;
dd->temp = ctx.result->temp;
dd->constant = ctx.result->constant;
dd->name = ctx.result->name;
}
else
{
int i;
//mark any temps free to avoid warnings.
for(i = 0; i < ctx.numlocals; i++)
{
if (ctx.locals[i].def)
QCC_FreeTemp(ctx.locals[i].def);
}
numstatements = statements; //remove the extra statements
}
return dd;
}
QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *newself, QCC_def_t *func, QCC_def_t *arglist[], QCC_type_t *argtypelist[], int argcount) //warning, the func could have no name set if it's a field call.
{
QCC_def_t *d, *oldret, *oself, *self;
@ -3681,6 +4073,17 @@ QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *newself, QCC_def_t *func, QCC
func->timescalled++;
if (!newself && func->constant && func->allowinline)
{
d = QCC_PR_Inline(func, arglist);
if (d)
{
optres_inlines++;
func->references++; //not really, but hey, the warning is stupid.
return d;
}
}
if (QCC_OPCodeValid(&pr_opcodes[OP_CALL1H]))
callconvention = OP_CALL1H; //FTE extended
else
@ -5538,6 +5941,7 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
}
else if (arraysize && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
{
//the only field of an array type is the 'length' property.
QCC_PR_Expect("length");
return QCC_PR_BuildRef(retbuf, REF_GLOBAL, QCC_MakeIntConst(arraysize), NULL, type_integer, true);
}
@ -5967,8 +6371,12 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
}
if (QCC_PR_CheckToken ("!"))
{
QCC_type_t *type;
e = QCC_PR_Expression (NOT_PRIORITY, EXPR_DISALLOW_COMMA|EXPR_WARN_ABOVE_1);
t = e->type->type;
type = e->type;
while(type->type == ev_accessor)
type = type->parentclass;
t = type->type;
if (t == ev_float)
e2 = QCC_PR_Statement (&pr_opcodes[OP_NOT_F], e, 0, NULL);
else if (t == ev_string)
@ -6080,7 +6488,7 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
}
if (QCC_PR_CheckToken ("("))
{
QCC_type_t *newtype;
QCC_type_t *newtype, *oldtype;
newtype = QCC_PR_ParseType(false, true);
if (newtype)
{
@ -6089,35 +6497,41 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
//and yeah, okay, use defs not refs. whatever.
e = QCC_PR_Expression (UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
oldtype = e->type;
//casting from an accessor uses the base type of that accessor (this allows us to properly read void* accessors)
if (oldtype->type == ev_accessor)
oldtype = oldtype->parentclass;
/*you may cast from a type to itself*/
if (!typecmp(e->type, newtype))
{
}
/*you may cast from const 0 to any type of same size for free (from either int or float for simplicity)*/
else if (newtype->size == e->type->size && (e->type->type == ev_integer || e->type->type == ev_float) && e->constant && !G_INT(e->ofs))
else if (newtype->size == oldtype->size && (oldtype->type == ev_integer || oldtype->type == ev_float) && e->constant && !G_INT(e->ofs))
{
e->references++;
//direct cast
return QCC_PR_BuildRef(retbuf, REF_GLOBAL, e, NULL, newtype, true);
}
/*cast from int->float will convert*/
else if (newtype->type == ev_float && e->type->type == ev_integer)
else if (newtype->type == ev_float && oldtype->type == ev_integer)
return QCC_DefToRef(retbuf, QCC_PR_Statement (&pr_opcodes[OP_CONV_ITOF], e, 0, NULL));
/*cast from float->int will convert*/
else if (newtype->type == ev_integer && e->type->type == ev_float)
else if (newtype->type == ev_integer && oldtype->type == ev_float)
return QCC_DefToRef(retbuf, QCC_PR_Statement (&pr_opcodes[OP_CONV_FTOI], e, 0, NULL));
/*you may freely cast between pointers (and ints, as this is explicit) (strings count as pointers - WARNING: some strings may not be expressable as pointers)*/
else if (
//pointers
((newtype->type == ev_pointer || newtype->type == ev_string || newtype->type == ev_integer) && (e->type->type == ev_pointer || e->type->type == ev_string || e->type->type == ev_integer))
((newtype->type == ev_pointer || newtype->type == ev_string || newtype->type == ev_integer) && (oldtype->type == ev_pointer || oldtype->type == ev_string || oldtype->type == ev_integer))
//ents/classs
|| (newtype->type == ev_entity && e->type->type == ev_entity)
|| (newtype->type == ev_entity && oldtype->type == ev_entity)
//functions can be explicitly cast from one to another
|| (newtype->type == ev_function && e->type->type == ev_function)
|| (newtype->type == ev_function && oldtype->type == ev_function)
//variants are fine too
|| (newtype->type == ev_variant || e->type->type == ev_variant)
|| (newtype->type == ev_accessor && newtype->parentclass->type == e->type->type)
|| (e->type->type == ev_accessor && e->type->parentclass->type == newtype->type)
|| (newtype->type == ev_variant || oldtype->type == ev_variant)
// || (newtype->type == ev_accessor && newtype->parentclass->type == e->type->type)
// || (e->type->type == ev_accessor && oldtype->parentclass->type == newtype->type)
|| !typecmp(oldtype, newtype)
)
{
e->references++;
@ -6159,6 +6573,7 @@ int QCC_canConv(QCC_def_t *from, etype_t to)
if (from->type->type == to)
return 0;
//triggers a warning. conversion works by using _x
if (from->type->type == ev_vector && to == ev_float)
return 4;
@ -6171,6 +6586,7 @@ int QCC_canConv(QCC_def_t *from, etype_t to)
}
}
//somewhat high penalty, ensures the other side is correct
if (from->type->type == ev_variant)
return 3;
@ -6183,6 +6599,7 @@ int QCC_canConv(QCC_def_t *from, etype_t to)
// if (from->type->type == ev_integer && to == ev_function)
// return 1;
//silently convert 0 to whatever as required.
if (from->constant && from->arraysize == 0 && from->type->size == ((to==ev_vector)?3:1) && (from->type->type == ev_integer || from->type->type == ev_float) && !G_INT(from->ofs))
return 2;
@ -7106,9 +7523,16 @@ QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_def_t *lhs, QCC_def_t *rhs, QCC_opcode_t *
}
else
{
if (numconversions>3)
QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", rhs->type->name, lhs->type->name);
op = bestop;
if (numconversions>3)
{
c=QCC_canConv(lhs, (*op->type_a)->type);
if (c>3)
QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", lhs->type->name, (*op->type_a)->name);
c=QCC_canConv(rhs, (*op->type_b)->type);
if (c>3)
QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion from %s to %s", rhs->type->name, (*op->type_a)->name);
}
}
return op;
}
@ -10264,6 +10688,7 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a
def->constant = !!(flags & GDF_CONST);
def->isstatic = !!(flags & GDF_STATIC);
def->strip = !!(flags & GDF_STRIP);
def->allowinline = !!(flags & GDF_INLINE);
def->ofs = ofs + type->size*a;
if (!first)
@ -10991,6 +11416,7 @@ void QCC_PR_ParseDefs (char *classname)
pbool nosave = false;
pbool allocatenew = true;
pbool inlinefunction = false;
pbool allowinline = false;
int arraysize;
unsigned int gd_flags;
@ -11442,6 +11868,8 @@ void QCC_PR_ParseDefs (char *classname)
noref=true;
else if (QCC_PR_CheckKeyword(keyword_nosave, "nosave"))
nosave = true;
else if (QCC_PR_CheckKeyword(keyword_nosave, "inline"))
allowinline = true;
else
break;
}
@ -11695,6 +12123,8 @@ void QCC_PR_ParseDefs (char *classname)
gd_flags |= GDF_CONST;
if (!nosave)
gd_flags |= GDF_SAVED;
if (allowinline)
gd_flags |= GDF_INLINE;
if (dynlength)
{

View File

@ -64,13 +64,13 @@ static void Q_strlcpy(char *dest, const char *src, int sizeofdest)
char *pr_punctuation[] =
// longer symbols must be before a shorter partial match
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)", "(-)", "|=", "&~=", "&=", "++", "--", "->", "^=", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", "~", ":", NULL};
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)", "(-)", "|=", "&~=", "&=", "++", "--", "->", "^=", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "%", "^", "~", ":", NULL};
char *pr_punctuationremap[] = //a nice bit of evilness.
//(+) -> |=
//-> -> .
//(-) -> &~=
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=", "&~=", "|=", "&~=", "&=", "++", "--", ".", "^=", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", "~", ":", NULL};
{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=", "&~=", "|=", "&~=", "&=", "++", "--", ".", "^=", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "%", "^", "~", ":", NULL};
// simple types. function types are dynamically allocated
QCC_type_t *type_void; //void
@ -4323,7 +4323,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
//accessors
if (QCC_PR_CheckKeyword (keyword_class, "accessor"))
{
char *parentname;
char parentname[256];
char *accessorname;
char *funcname;
@ -4347,8 +4347,11 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (QCC_PR_CheckToken(":"))
{
parentname = QCC_PR_ParseName();
type = QCC_TypeForName(parentname);
type = QCC_PR_ParseType(false, false);
if (type)
TypeName(type, parentname, sizeof(parentname));
else
strcpy(parentname, "??");
if (!type || type->type == ev_struct || type->type == ev_union)
QCC_PR_ParseError(ERR_NOTANAME, "Accessor %s cannot be based upon %s", accessorname, parentname);
@ -4384,10 +4387,13 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
int args;
char *indexname;
pbool isref;
pbool isinline;
do
{
isinline = QCC_PR_CheckName("inline");
if (QCC_PR_CheckName("set"))
setnotget = true;
else if (QCC_PR_CheckName("get"))
@ -4400,6 +4406,8 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
fieldtype = QCC_TypeForName(fieldtypename);
if (!fieldtype)
QCC_PR_ParseError(ERR_NOTATYPE, "Invalid type: %s", fieldtypename);
while(QCC_PR_CheckToken("*"))
fieldtype = QCC_PR_PointerType(fieldtype);
if (pr_token_type != tt_punct)
{
@ -4454,7 +4462,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
char funcname[256];
QC_snprintfz(funcname, sizeof(funcname), "%s::%s_%s", newt->name, setnotget?"set":"get", accessorname);
def = QCC_PR_GetDef(functype, funcname, NULL, true, 0, GDF_CONST);
def = QCC_PR_GetDef(functype, funcname, NULL, true, 0, GDF_CONST | (isinline?GDF_INLINE:0));
pr_scope = def;
//pr_classtype = newt;
@ -4492,7 +4500,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
else
{
funcname = QCC_PR_ParseName();
def = QCC_PR_GetDef(functype, funcname, NULL, true, 0, 0);
def = QCC_PR_GetDef(functype, funcname, NULL, true, 0, GDF_CONST|(isinline?GDF_INLINE:0));
if (!def)
QCC_Error(ERR_NOFUNC, "%s::set_%s: %s was not defined", newt->name, accessorname, funcname);
}
@ -4515,6 +4523,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (acc->getset_func[setnotget])
QCC_Error(ERR_TOOMANYINITIALISERS, "%s::%s_%s already declared", newt->name, setnotget?"set":"get", accessorname);
acc->getset_func[setnotget] = def;
acc->getset_isref[setnotget] = isref;
} while (QCC_PR_CheckToken(",") || QCC_PR_CheckToken(";"));
QCC_PR_Expect("}");
}

View File

@ -1,3 +1,4 @@
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
@ -5,6 +6,7 @@
#include <richedit.h>
#include <stdio.h>
#include <sys/stat.h>
#include <shlobj.h>
#include "qcc.h"
#include "gui.h"
@ -581,6 +583,17 @@ LRESULT CALLBACK MySubclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
RunEngine();
return 0;
}
if (wParam == VK_F7)
{
buttons[ID_COMPILE].washit = true;
return 0;
}
if (wParam == VK_F8)
{
// if (!EngineCommandf("qcjump\n"))
// RunEngine();
return 0;
}
if (wParam == VK_F9)
{
editor_t *editor;
@ -603,7 +616,12 @@ LRESULT CALLBACK MySubclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
}
if (wParam == VK_F11)
{
EngineCommandf("qcstep\n");
EngineCommandf("qcstep over\n");
return 0;
}
if (wParam == VK_F11)
{
EngineCommandf("qcstep into\n");
return 0;
}
}
@ -728,7 +746,7 @@ HWND CreateAnEditControl(HWND parent, pbool *scintillaokay)
SendMessage(newc, SCI_STYLESETFORE, SCE_C_ESCAPESEQUENCE, RGB(0xA0, 0x10, 0x10));
SendMessage(newc, SCI_STYLESETFORE, STYLE_BRACELIGHT, RGB(0x00, 0x00, 0x3F));
SendMessage(newc, SCI_STYLESETBACK, STYLE_BRACELIGHT, RGB(0xaf, 0xaf, 0xaf));
SendMessage(newc, SCI_STYLESETBACK, STYLE_BRACELIGHT, RGB(0xef, 0xaf, 0xaf));
SendMessage(newc, SCI_STYLESETBOLD, STYLE_BRACELIGHT, TRUE);
SendMessage(newc, SCI_STYLESETFORE, STYLE_BRACEBAD, RGB(0x3F, 0x00, 0x00));
SendMessage(newc, SCI_STYLESETBACK, STYLE_BRACEBAD, RGB(0xff, 0xaf, 0xaf));
@ -740,6 +758,7 @@ HWND CreateAnEditControl(HWND parent, pbool *scintillaokay)
"nosave shared state optional string "
"struct switch thinktime until loop "
"typedef union var vector void "
"accessor get set inline "
"virtual nonvirtual class static nonstatic local return"
);
@ -2553,6 +2572,119 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message,
}
return 0;
}
static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData)
{ //'stolen' from microsoft's knowledge base.
//required to work around microsoft being annoying.
TCHAR szDir[MAX_PATH];
char *foo;
switch(uMsg)
{
case BFFM_INITIALIZED:
if (GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR), szDir))
{
foo = strrchr(szDir, '\\');
if (foo)
*foo = 0;
foo = strrchr(szDir, '\\');
if (foo)
*foo = 0;
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
}
break;
case BFFM_SELCHANGED:
if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir))
{
while(foo = strchr(szDir, '\\'))
*foo = '/';
//fixme: verify that id1 is a subdir perhaps?
SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir);
}
break;
}
return 0;
}
void PromptForEngine(int force)
{
#ifndef OFN_DONTADDTORECENT
#define OFN_DONTADDTORECENT 0x02000000
#endif
char workingdir[MAX_PATH+10];
GetCurrentDirectory(sizeof(workingdir)-1, workingdir);
if (!*enginebasedir || force==1)
{
BROWSEINFO bi;
LPITEMIDLIST il;
memset(&bi, 0, sizeof(bi));
bi.hwndOwner = mainwindow;
bi.pidlRoot = NULL;
bi.pszDisplayName = workingdir;
bi.lpszTitle = "Please locate your base directory";
bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT;
bi.lpfn = StupidBrowseCallbackProc;
bi.lParam = 0;
bi.iImage = 0;
il = SHBrowseForFolder(&bi);
if (il)
{
SHGetPathFromIDList(il, enginebasedir);
CoTaskMemFree(il);
}
else
return;
QCC_RegSetValue(HKEY_CURRENT_USER, "Software\\FTE QuakeWorld\\fteqccgui", "enginebasedir", REG_SZ, enginebasedir, strlen(enginebasedir));
}
if (!*enginebinary || force==2)
{
char *s;
char initialdir[MAX_PATH+10];
OPENFILENAME ofn;
pbool okay;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = mainwindow;
ofn.hInstance = ghInstance;
ofn.lpstrFile = enginebinary;
ofn.Flags = OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_DONTADDTORECENT;
ofn.lpstrTitle = "Please choose an engine";
ofn.nMaxFile = sizeof(enginebinary)-1;
ofn.lpstrFilter = "Executables\0*.exe\0All files\0*.*\0";
strcpy(enginebinary, "fteglqw.exe");
if (enginebasedir[0] == '.' && enginebasedir[1] == '.' && (!enginebasedir[2] || enginebasedir[2] == '/' || enginebasedir[2] == '\\'))
{
_snprintf(initialdir, sizeof(initialdir), "%s/%s", workingdir, enginebasedir);
strcat(initialdir, "/");
strcat(initialdir, enginebasedir);
}
else
strcpy(initialdir, enginebasedir);
//and the fuck-you-microsoft loop
for (s = initialdir; *s; s++)
if (*s == '/')
*s = '\\';
ofn.lpstrInitialDir = initialdir;
okay = GetOpenFileName(&ofn);
while (!okay)
{
switch(CommDlgExtendedError())
{
case FNERR_INVALIDFILENAME:
*enginebinary = 0;
okay = GetOpenFileName(&ofn);
continue;
}
break;
}
//undo any damage caused by microsoft's stupidity
SetCurrentDirectory(workingdir);
if (!okay)
return;
QCC_RegSetValue(HKEY_CURRENT_USER, "Software\\FTE QuakeWorld\\fteqccgui", "enginebinary", REG_SZ, enginebinary, strlen(enginebinary));
}
}
void RunEngine(void)
{
int embedtype = 0; //0 has focus issues.
@ -2561,6 +2693,8 @@ void RunEngine(void)
WNDCLASS wndclass;
MDICREATESTRUCT mcs;
PromptForEngine(0);
memset(&wndclass, 0, sizeof(wndclass));
wndclass.style = 0;
wndclass.lpfnWndProc = EngineWndProc;
@ -3209,6 +3343,11 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
AppendMenu(m, 0, IDM_CASCADE, "Cascade");
AppendMenu(m, 0, IDM_TILE_HORIZ, "Tile Horizontally");
AppendMenu(m, 0, IDM_TILE_VERT, "Tile Vertically");
AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&Debug");
AppendMenu(m, 0, IDM_CASCADE, "Rebuild\tF7");
AppendMenu(m, 0, IDM_TILE_HORIZ, "Run/Resume\tF5");
AppendMenu(m, 0, IDM_TILE_HORIZ, "Step Into\tF11");
AppendMenu(m, 0, IDM_TILE_VERT, "Set Breakpoint\tF9");
AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&Help");
AppendMenu(m, 0, IDM_ABOUT, "About");
@ -3915,9 +4054,9 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
GUI_SetDefaultOpts();
if (!QCC_RegGetStringValue(HKEY_CURRENT_USER, "Software\\FTE QuakeWorld\\fteqccgui", "enginebinary", enginebinary, sizeof(enginebinary)))
strcpy(enginebinary, "fteglqw.exe");
strcpy(enginebinary, "");
if (!QCC_RegGetStringValue(HKEY_CURRENT_USER, "Software\\FTE QuakeWorld\\fteqccgui", "enginebasedir", enginebasedir, sizeof(enginebasedir)))
strcpy(enginebasedir, "../..");
strcpy(enginebasedir, "");
if (!QCC_RegGetStringValue(HKEY_CURRENT_USER, "Software\\FTE QuakeWorld\\fteqccgui", "enginecommandline", enginecommandline, sizeof(enginecommandline)))
strcpy(enginecommandline, "-window +map start -nohome");

View File

@ -728,7 +728,7 @@ pbool QCC_WriteData (int crc)
{
if (numpr_globals >= 32768) //not much of a different format. Rewrite output to get it working on original executors?
printf("Globals exceeds 32k - an enhanced QCVM will be required\n");
else
else if (verbose)
printf("Progs should run on any QuakeC VM\n");
break;
}
@ -3219,6 +3219,7 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine
optres_stripfunctions = 0;
optres_locals_overlapping = 0;
optres_logicops = 0;
optres_inlines = 0;
optres_test1 = 0;
optres_test2 = 0;
@ -3706,6 +3707,8 @@ void QCC_FinishCompile(void)
printf("optres_locals_overlapping %i\n", optres_locals_overlapping);
if (optres_logicops)
printf("optres_logicops %i\n", optres_logicops);
if (optres_inlines)
printf("optres_inlines %i\n", optres_inlines);
if (optres_test1)

View File

@ -58,6 +58,7 @@ cvar_t saved3 = CVARF("saved3", "0", CVAR_ARCHIVE);
cvar_t saved4 = CVARF("saved4", "0", CVAR_ARCHIVE);
cvar_t temp1 = CVARF("temp1", "0", CVAR_ARCHIVE);
cvar_t noexit = CVAR("noexit", "0");
extern cvar_t sv_specprint;
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.");
@ -2001,7 +2002,7 @@ qbyte *PR_OpenFile(char *filename, qbyte *buffer)
#define RETURN_SSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_SetString(prinst, s)) //static - exe will not change it.
#define RETURN_TSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_TempString(prinst, s)) //temp (static but cycle buffers)
#define RETURN_CSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_SetString(prinst, s)) //semi-permanant. (hash tables?)
#define RETURN_PSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_NewString(prinst, s, 0)) //permanant
#define RETURN_PSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_NewString(prinst, s)) //permanant
/*
===============================================================================
@ -2593,6 +2594,26 @@ static void QCBUILTIN PF_sprint (pubprogfuncs_t *prinst, struct globalvars_s *pr
client = &svs.clients[entnum-1];
SV_ClientPrintf (client, level, "%s", s);
if (sv_specprint.ival & SPECPRINT_SPRINT)
{
client_t *spec;
unsigned int i;
for (i = 0, spec = svs.clients; i < sv.allocated_client_slots; i++, spec++)
{
if (spec->state != cs_spawned || !spec->spectator)
continue;
if (spec->spec_track == entnum && (spec->spec_print & SPECPRINT_SPRINT))
{
if (level < spec->messagelevel)
continue;
if (spec->controller)
SV_PrintToClient(spec->controller, level, s);
else
SV_PrintToClient(spec, level, s);
}
}
}
}
//When a client is backbuffered, it's generally not a brilliant plan to send a bazillion stuffcmds. You have been warned.
@ -2657,6 +2678,22 @@ void PF_centerprint_Internal (int entnum, qboolean plaque, const char *s)
cl->centerprintstring = Z_Malloc(slen+1);
strcpy(cl->centerprintstring, s);
}
if (sv_specprint.ival & SPECPRINT_CENTERPRINT)
{
client_t *spec;
unsigned int i;
for (i = 0, spec = svs.clients; i < sv.allocated_client_slots; i++, spec++)
{
if (spec->state != cs_spawned || !spec->spectator || spec == cl)
continue;
if (spec->spec_track == entnum && (spec->spec_print & SPECPRINT_CENTERPRINT))
{
Z_Free(spec->centerprintstring);
spec->centerprintstring = Z_StrDup(cl->centerprintstring);
}
}
}
}
static void QCBUILTIN PF_centerprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -3380,6 +3417,9 @@ void PF_stuffcmd_Internal(int entnum, const char *str)
return;
}
//this block is a hack to 'fix' nq mods that expect all clients to support nq commands - but we're a qw engine.
//FIXME: should buffer the entire command instead.
if (progstype != PROG_QW)
{
if (!strncmp(str, "color ", 6)) //okay, so this is a hack, but it fixes the qw scoreboard
@ -3405,7 +3445,7 @@ void PF_stuffcmd_Internal(int entnum, const char *str)
default: tname = va("t%i", team); break; //good job our va has multiple buffers
}
ClientReliableWrite_Begin (cl, svc_stufftext, 2+strlen("team XXXXXX\n"));
ClientReliableWrite_Begin (cl, svc_stufftext, 2+strlen("team \n")+strlen(tname));
ClientReliableWrite_String (cl, va("team %s\n", tname));
ClientReliableWrite_Begin (cl, svc_stufftext, 2+strlen("color "));
@ -3415,29 +3455,7 @@ void PF_stuffcmd_Internal(int entnum, const char *str)
slen = strlen(str);
if (cl->controller)
{ //this is a slave client.
//find the right number and send.
int pnum = 0;
client_t *sp;
for (sp = cl->controller; sp; sp = sp->controlled)
{
if (sp == cl)
break;
pnum++;
}
sp = cl->controller;
ClientReliableWrite_Begin (sp, svcfte_choosesplitclient, 4 + slen);
ClientReliableWrite_Byte (sp, pnum);
ClientReliableWrite_Byte (sp, svc_stufftext);
ClientReliableWrite_String (sp, str);
}
else
{
ClientReliableWrite_Begin (cl, svc_stufftext, 2+slen);
ClientReliableWrite_String (cl, str);
}
SV_StuffcmdToClient(cl, str);
if (sv.mvdrecording)
{
@ -3445,6 +3463,20 @@ void PF_stuffcmd_Internal(int entnum, const char *str)
MSG_WriteByte (msg, svc_stufftext);
MSG_WriteString (msg, str);
}
//this seems a little dangerous. v_cshift could leave a spectator's machine unusable if they switch players at unfortunate times.
if (sv_specprint.ival & SPECPRINT_STUFFCMD)
{
client_t *spec;
unsigned int i;
for (i = 0, spec = svs.clients; i < sv.allocated_client_slots; i++, spec++)
{
if (spec->state != cs_spawned || !spec->spectator)
continue;
if (spec->spec_track == entnum && (spec->spec_print & SPECPRINT_STUFFCMD))
SV_StuffcmdToClient(spec, str);
}
}
}
/*
@ -5414,7 +5446,7 @@ static void QCBUILTIN PF_Ignore(pubprogfuncs_t *prinst, struct globalvars_s *pr_
}
#ifndef QUAKETC
static void QCBUILTIN PF_newstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //mvdsv
static void QCBUILTIN PF_mvdsv_newstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //mvdsv
{
char *s;
int len;
@ -5429,6 +5461,10 @@ static void QCBUILTIN PF_newstring(pubprogfuncs_t *prinst, struct globalvars_s *
G_INT(OFS_RETURN) = (char*)s - prinst->stringtable;
strcpy(s, in);
}
static void QCBUILTIN PF_mvdsv_freestring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //mvdsv
{
prinst->AddressableFree(prinst, prinst->stringtable + G_INT(OFS_PARM0));
}
#endif
// warning: PF_strcatp defined but not used
@ -9291,8 +9327,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"logfrag", PF_logfrag, 0, 79, 0, 79, "void(entity killer, entity killee)"}, //79
// Tomaz - QuakeC String Manipulation Begin
{"tq_zone", PF_dupstring, 0, 0, 0, 79, D("string(string s)",NULL), true}, //79
{"tq_unzone", PF_forgetstring, 0, 0, 0, 80, D("void(string s)",NULL), true}, //80
{"tq_zone", PF_strzone, 0, 0, 0, 79, D("string(string s)",NULL), true}, //79
{"tq_unzone", PF_strunzone, 0, 0, 0, 80, D("void(string s)",NULL), true}, //80
{"tq_stof", PF_stof, 0, 0, 0, 81, D("float(string s)",NULL), true}, //81
{"tq_strcat", PF_strcat, 0, 0, 0, 82, D("string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)",NULL), true}, //82
{"tq_substring", PF_substring, 0, 0, 0, 83, D("string(string str, float start, float len)",NULL), true}, //83
@ -9330,8 +9366,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"mvdstrlen", PF_strlen, 0, 0, 0, 90, D("float(string s)",NULL), true},
{"str2byte", PF_str2byte, 0, 0, 0, 91, D("float(string str)",NULL), true},
{"str2short", PF_str2short, 0, 0, 0, 92, D("float(string str)",NULL), true},
{"mvdnewstr", PF_newstring, 0, 0, 0, 93, D("string(string s, optional float bufsize)",NULL), true},
{"mvdfreestr", PF_forgetstring, 0, 0, 0, 94, D("void(string s)",NULL), true},
{"mvdnewstr", PF_mvdsv_newstring, 0, 0, 0, 93, D("string(string s, optional float bufsize)",NULL), true},
{"mvdfreestr", PF_mvdsv_freestring,0, 0, 0, 94, D("void(string s)",NULL), true},
{"conprint", PF_conprint, 0, 0, 0, 95, D("void(string s, ...)",NULL), true},
{"readcmd", PF_readcmd, 0, 0, 0, 96, D("string(string str)",NULL), true},
{"mvdstrcpy", PF_MVDSV_strcpy, 0, 0, 0, 97, D("void(string dst, string src)",NULL), true},
@ -9425,13 +9461,18 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"strcat", PF_strcat, 0, 0, 0, 115, "string(string s1, optional string s2, ...)"}, // (FRIK_FILE)
{"substring", PF_substring, 0, 0, 0, 116, "string(string s, float start, float length)"}, // (FRIK_FILE)
{"stov", PF_stov, 0, 0, 0, 117, "vector(string s)"}, // (FRIK_FILE)
{"strzone", PF_dupstring, 0, 0, 0, 118, "string(string s, ...)"}, // (FRIK_FILE)
{"strunzone", PF_forgetstring, 0, 0, 0, 119, "void(string s)"}, // (FRIK_FILE)
#ifdef QCGC
{"strzone", PF_strzone, 0, 0, 0, 118, D("string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods.")}, // (FRIK_FILE)
{"strunzone", PF_strunzone, 0, 0, 0, 119, D("void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing.")}, // (FRIK_FILE)
#else
{"strzone", PF_strzone, 0, 0, 0, 118, D("string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope).")}, // (FRIK_FILE)
{"strunzone", PF_strunzone, 0, 0, 0, 119, D("void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game.")}, // (FRIK_FILE)
#endif
//end frikfile
//these are telejano's
{"cvar_setf", PF_cvar_setf, 0, 0, 0, 176, "void(string cvar, float val)"},
{"localsound", PF_LocalSound, 0, 0, 0, 177, D("", NULL), true},// #177
{"localsound", PF_LocalSound, 0, 0, 0, 177, D("", "Plays a sound... on the server."), true},// #177
//end telejano
//fte extras
@ -9441,7 +9482,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"externvalue", PF_externvalue, 0, 0, 0, 203, D("__variant(float prnum, string varname)", "Reads a global in the named progs by the name of that global.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")},
{"externset", PF_externset, 0, 0, 0, 204, D("void(float prnum, __variant newval, string varname)", "Sets a global in the named progs by name.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")},
{"externrefcall", PF_externrefcall, 0, 0, 0, 205, D("__variant(float prnum, void() func, ...)","Calls a function between progs by its reference. No longer needed as direct function calls now switch progs context automatically, and have done for a long time. There is no remaining merit for this function."), true},
{"instr", PF_instr, 0, 0, 0, 206, D("float(string input, string token)", "Returns substring(input, strstrpos(input, token), -1), or the null string if token was not found in input. You're probably better off using strstrpos.")},
{"instr", PF_instr, 0, 0, 0, 206, D("float(string input, string token)", "Returns substring(input, strstrpos(input, token), -1), or the null string if token was not found in input. You're probably better off using strstrpos."), true},
{"openportal", PF_OpenPortal, 0, 0, 0, 207, D("void(entity portal, float state)", "Opens or closes the portals associated with a door or some such on q2 or q3 maps. On Q2BSPs, the entity should be the 'func_areaportal' entity - its style field will say which portal to open. On Q3BSPs, the entity is the door itself, the portal will be determined by the two areas found from a preceding setorigin call.")},
{"RegisterTempEnt", PF_RegisterTEnt, 0, 0, 0, 208, "float(float attributes, string effectname, ...)"},
@ -9504,6 +9545,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"rotatevectorsbytag", PF_Fixme, 0, 0, 0, 244, "vector(entity ent, float tagnum)"},
{"mod", PF_mod, 0, 0, 0, 245, "float(float dividend, float divisor)"},
// {"empty", PF_Fixme, 0, 0, 0, 245, "void()"},
// {"empty", PF_Fixme, 0, 0, 0, 246, "void()"},
// {"empty", PF_Fixme, 0, 0, 0, 247, "void()"},
@ -9543,7 +9585,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"terrain_edit", PF_terrain_edit, 0, 0, 0, 278, D("void(float action, optional vector pos, optional float radius, optional float quant, ...)", "Realtime terrain editing. Actions are the TEREDIT_ constants.")},// (??FTE_TERRAIN_EDIT??
{"touchtriggers", PF_touchtriggers, 0, 0, 0, 279, D("void()", "Triggers a touch events between self and every entity that it is in contact with. This should typically just be the triggers touch functions.")},//
{"writefloat", PF_WriteFloat, 0, 0, 0, 280, "void(float buf, float fl)"},//
{"WriteFloat", PF_WriteFloat, 0, 0, 0, 280, "void(float buf, float fl)"},//
{"skel_ragupdate", PF_skel_ragedit, 0, 0, 0, 281, D("float(entity skelent, string dollcmd, float animskel)", "Updates the skeletal object attached to the entity according to its origin and other properties.\nif animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results.\nIf dollcmd is not set, the ragdoll will update (this should be done each frame).\nIf the doll is updated without having a valid doll, the model's default .doll will be instanciated.\ncommands:\n doll foo.doll : sets up the entity to use the named doll file\n dollstring TEXT : uses the doll file directly embedded within qc, with that extra prefix.\n cleardoll : uninstanciates the doll without destroying the skeletal object.\n animate 0.5 : specifies the strength of the ragdoll as a whole \n animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body).\n enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter.")}, // (FTE_CSQC_RAGDOLL)
{"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, D("float*(float skel)", "Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly).")},// (FTE_QC_RAGDOLL)
{"skel_set_bone_world",PF_skel_set_bone_world,0,0, 0, 283, D("void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up)", "Sets the world position of a bone within the given entity's attached skeletal object. The world position is dependant upon the owning entity's position. If no orientation argument is specified, v_forward+v_right+v_up are used for the orientation instead. If 1 is specified, it is understood as angles. If 3 are specified, they are the forawrd/right/up vectors to use.")},
@ -11101,6 +11143,14 @@ void PR_DumpPlatform_f(void)
);
for (i = 0; i < QSG_Extensions_count; i++)
{
if (QSG_Extensions[i].description)
VFS_PRINTF(f, "#define %s /* %s */\n", QSG_Extensions[i].name, QSG_Extensions[i].description);
else
VFS_PRINTF(f, "#define %s\n", QSG_Extensions[i].name);
}
if (accessors)
{
VFS_PRINTF(f, "accessor strbuf : float;\n");

View File

@ -11,24 +11,29 @@ extern cvar_t pr_enable_profiling;
void SV_Savegame_f (void);
//Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current
void SV_SavegameComment (char *text)
void SV_SavegameComment (char *text, size_t textsize)
{
int i;
char kills[20];
char datetime[64];
time_t timeval;
char *mapname = sv.mapname;
for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
for (i=0 ; i<textsize-1 ; i++)
text[i] = ' ';
text[textsize-1] = '\0';
if (!mapname)
strcpy( text, "Unnamed_Level");
else
{
i = strlen(mapname);
if (i > SAVEGAME_COMMENT_LENGTH)
i = SAVEGAME_COMMENT_LENGTH;
if (i > 22)
i = 22;
memcpy (text, mapname, i);
}
kills[0] = '\0';
#ifdef Q2SERVER
if (ge) //q2
{
@ -39,21 +44,32 @@ void SV_SavegameComment (char *text)
#ifdef HLSERVER
if (svs.gametype == GT_HALFLIFE)
{
sprintf (kills,"kills:moo");
sprintf (kills,"");
}
else
#endif
sprintf (kills,"kills:%3i/%3i", (int)pr_global_struct->killed_monsters, (int)pr_global_struct->total_monsters);
{
if ((int)pr_global_struct->killed_monsters || (int)pr_global_struct->total_monsters)
sprintf (kills,"kills:%3i/%3i", (int)pr_global_struct->killed_monsters, (int)pr_global_struct->total_monsters);
}
time(&timeval);
strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", localtime( &timeval ));
memcpy (text+22, kills, strlen(kills));
if (textsize > 39)
{
Q_strncpyz(text+39, datetime, textsize-39);
}
// convert space to _ to make stdio happy
for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
for (i=0 ; i<textsize-1 ; i++)
{
if (text[i] == ' ')
text[i] = '_';
else if (text[i] == '\n')
text[i] = '\0';
}
text[SAVEGAME_COMMENT_LENGTH] = '\0';
text[textsize-1] = '\0';
}
//expects the version to have already been parsed
@ -198,7 +214,6 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
VFS_GETS(f, str, sizeof(str));
pt = atoi(str);
// this silliness is so we can load 1.06 save files, which have float skill values
VFS_GETS(f, str, sizeof(str));
Cvar_SetValue (Cvar_FindVar("skill"), atof(str));
@ -401,7 +416,7 @@ void SV_LegacySavegame_f (void)
VFS_PRINTF(f, "%i\n", version);
SV_SavegameComment (comment);
SV_SavegameComment (comment, sizeof(comment));
VFS_PRINTF(f, "%s\n", comment);
if (version != SAVEGAME_VERSION)
@ -760,7 +775,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea
if (!isloadgame)
{
eval = PR_FindGlobal(svprogfuncs, "startspot", 0, NULL);
if (eval) eval->_int = (int)PR_NewString(svprogfuncs, startspot, 0);
if (eval) eval->_int = (int)PR_NewString(svprogfuncs, startspot);
eval = PR_FindGlobal(svprogfuncs, "ClientReEnter", 0, NULL);
if (eval)
@ -910,7 +925,7 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame)
}
VFS_PRINTF (f, "%i\n", version);
SV_SavegameComment (comment);
SV_SavegameComment (comment, sizeof(comment));
VFS_PRINTF (f, "%s\n", comment);
if (!dontharmgame)
@ -1053,11 +1068,12 @@ void SV_Savegame (char *savename)
extern cvar_t temp1;
extern cvar_t noexit;
extern cvar_t pr_maxedicts;
extern cvar_t scr_sshot_type;
client_t *cl;
int clnum;
char comment[SAVEGAME_COMMENT_LENGTH+1];
char comment[(SAVEGAME_COMMENT_LENGTH+1)*2];
vfsfile_t *f;
int len;
levelcache_t *cache;
@ -1092,7 +1108,7 @@ void SV_Savegame (char *savename)
Con_Printf("Couldn't open file saves/%s/info.fsv\n", savename);
return;
}
SV_SavegameComment(comment);
SV_SavegameComment(comment, sizeof(comment));
VFS_PRINTF (f, "%d\n", FTESAVEGAME_VERSION+svs.gametype);
VFS_PRINTF (f, "%s\n", comment);
@ -1165,6 +1181,61 @@ void SV_Savegame (char *savename)
VFS_CLOSE(f);
#ifndef SERVERONLY
//try to save screenshots automagically.
savefilename = va("saves/%s/screeny.%s", savename, scr_sshot_type.string);
FS_Remove(savefilename, FS_GAMEONLY);
if (cls.state == ca_active && qrenderer > QR_NONE)
{
int width;
int height;
qbyte *rgbbuffer;
image_t *img;
//poke the various modes into redrawing the screen (without huds), to avoid any menus or console drawn over the top of the current backbuffer.
//FIXME: clear-to-black first
qboolean okay = false;
#ifdef VM_CG
if (!okay && CG_Refresh())
okay = true;
#endif
#ifdef CSQC_DAT
if (!okay && CSQC_DrawView())
okay = true;
#endif
if (!okay && r_worldentity.model)
{
V_RenderView ();
okay = true;
}
//okay, we drew something, we're good to save a screeny.
if (okay)
{
rgbbuffer = VID_GetRGBInfo(0, &width, &height);
if (rgbbuffer)
{
SCR_ScreenShot(savefilename, rgbbuffer, width, height);
BZ_Free(rgbbuffer);
//if any menu code has the shader loaded, we want to avoid them using a cache.
//hopefully the menu code will unload as it goes, because these screenshots could be truely massive, as they're taken at screen resolution.
//should probably use a smaller fbo or something, but whatever.
img = Image_FindTexture(va("saves/%s/screeny.%s", savename, "tga"), NULL, 0);
if (img)
{
if (Image_UnloadTexture(img))
{
//and then reload it so that any shaders using it don't get confused
Image_GetTexture(va("saves/%s/screeny.%s", savename, "tga"), NULL, 0, NULL, NULL, 0, 0, TF_INVALID);
}
}
}
}
}
#endif
#ifdef Q2SERVER
//save the player's inventory and other map-persistant state that is owned by the gamecode.
if (ge)
@ -1185,7 +1256,10 @@ void SV_Savegame (char *savename)
void SV_Savegame_f (void)
{
SV_Savegame(Cmd_Argv(1));
if (Cmd_Argc() <= 2)
SV_Savegame(Cmd_Argv(1));
else
Con_Printf("%s: invalid number of arguments\n", Cmd_Argv(0));
}
void SV_Loadgame_f (void)
{

View File

@ -302,6 +302,9 @@ typedef struct
packet_entities_t entities; //package containing entity states that were sent in this frame, for deltaing
unsigned int *resendentnum; //the number of each entity that was sent in this frame
unsigned int *resendentbits; //the bits of each entity that were sent in this frame
unsigned short resendstats[32];//the number of each entity that was sent in this frame
unsigned int numresendstats; //the bits of each entity that were sent in this frame
} client_frame_t;
#ifdef Q2SERVER
@ -362,6 +365,11 @@ enum
PLIMIT_SOUNDS = 1u<<2
};
//client_t->spec_print + sv_specprint
#define SPECPRINT_CENTERPRINT 0x1
#define SPECPRINT_SPRINT 0x2
#define SPECPRINT_STUFFCMD 0x4
typedef struct client_s
{
client_conn_state_t state;
@ -440,6 +448,7 @@ typedef struct client_s
// client known data for deltas
int old_frags;
unsigned int pendingstats[((MAX_CL_STATS*2) + 31)>>5]; //these are the stats that have changed and that need sending/resending
int statsi[MAX_CL_STATS];
float statsf[MAX_CL_STATS];
char *statss[MAX_CL_STATS];
@ -467,6 +476,8 @@ typedef struct client_s
int spec_track; // entnum of player tracking
unsigned int spec_print; //bitfield for things this spectator should see that were directed to the player that they're tracking.
#ifdef Q3SERVER
int gamestatesequence; //the sequence number the initial gamestate was sent in.
int last_server_command_num;
@ -571,9 +582,12 @@ typedef struct client_s
} protocol;
//speed cheat testing
#define NEWSPEEDCHEATPROT
int msecs;
#ifndef NEWSPEEDCHEATPROT
int msec_cheating;
float last_check;
#endif
qboolean gibfilter;
@ -1110,7 +1124,7 @@ void SV_StartSound (int ent, vec3_t origin, int seenmask, int channel, const cha
void SVQ1_StartSound (float *origin, wedict_t *entity, int channel, const char *sample, int volume, float attenuation, int pitchadj);
void SV_PrintToClient(client_t *cl, int level, const char *string);
void SV_TPrintToClient(client_t *cl, int level, const char *string);
void SV_StuffcmdToClient(client_t *cl, char *string);
void SV_StuffcmdToClient(client_t *cl, const char *string);
void VARGS SV_ClientPrintf (client_t *cl, int level, char *fmt, ...) LIKEPRINTF(3);
void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t text, ...);
void VARGS SV_BroadcastPrintf (int level, char *fmt, ...) LIKEPRINTF(2);

View File

@ -233,9 +233,9 @@ float SV_ChatFunc(const char *func) //parse a condition/function
if (*com_token == ',')
continue;
if (com_tokentype == TTP_STRING)
G_INT(parm) = PR_NewString(svprogfuncs, com_token, 0);
G_INT(parm) = PR_NewString(svprogfuncs, com_token);
else if (!strcmp(com_token, "ent"))
SetGlobalEdict(svprogfuncs, host_client->chat.edict, parm);
G_INT(parm) = EDICT_TO_PROG(svprogfuncs, host_client->chat.edict);
else
G_FLOAT(parm) = SV_ChatFunc(os);

View File

@ -464,6 +464,7 @@ void SV_CSQC_DroppedPacket(client_t *client, int sequence)
return;
}
//lost entities need flagging for a resend
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
unsigned int *f = client->frameunion.frames[sequence & UPDATE_MASK].resendentbits;
@ -482,6 +483,30 @@ void SV_CSQC_DroppedPacket(client_t *client, int sequence)
}
client->frameunion.frames[sequence & UPDATE_MASK].entities.num_entities = 0;
}
//lost stats do too
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
client_t *sp;
unsigned short *n = client->frameunion.frames[sequence & UPDATE_MASK].resendstats;
i = client->frameunion.frames[sequence & UPDATE_MASK].numresendstats;
while(i-->0)
{
unsigned short s = n[i];
if (s & 0xf000)
{
sp = client;
while (s & 0xf000)
{
s -= 0x1000;
sp = sp->controlled;
}
sp->pendingstats[s>>5u] |= 1u << (s & 0x1fu);
}
else
client->pendingstats[s>>5u] |= 1u << (s & 0x1fu);
}
client->frameunion.frames[sequence & UPDATE_MASK].numresendstats = 0;
}
if (!(client->csqcactive)) //we don't need this, but it might be a little faster.
return;
@ -506,6 +531,9 @@ void SV_CSQC_DropAll(client_t *client)
for (i = 0; i < sv.world.num_edicts; i++)
client->csqcentversions[i]--; //do that update thang (but later).
//we don't know which stats were on the wire, resend all. :(
memset(client->pendingstats, 0xff, sizeof(client->pendingstats));
}
//=============================================================================
@ -2870,10 +2898,10 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
VectorCopy (ent->v->origin, state->origin);
VectorCopy (ent->v->angles, state->angles);
if ((state->number-1) < (unsigned int)sv.allocated_client_slots && (client == &svs.clients[state->number-1] || client == svs.clients[state->number-1].controller))
state->u.q1.weaponframe = ent->v->weaponframe;
else
state->u.q1.weaponframe = 0;
state->u.q1.weaponframe = 0;
if ((state->number-1) < (unsigned int)sv.allocated_client_slots && (client == &svs.clients[state->number-1] || client == svs.clients[state->number-1].controller || (client && (!client->edict || client->spec_track == state->number))))
if (!client || !(client->fteprotocolextensions2 & PEXT2_PREDINFO))
state->u.q1.weaponframe = ent->v->weaponframe;
if ((state->number-1) < (unsigned int)sv.allocated_client_slots && ent->v->movetype)
{
client_t *cl = &svs.clients[state->number-1];
@ -2900,7 +2928,13 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
}
//fixme: deal with fixangles
VectorCopy (ent->v->v_angle, state->angles);
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
if (state->u.q1.pmovetype && (state->u.q1.pmovetype != MOVETYPE_TOSS && state->u.q1.pmovetype != MOVETYPE_BOUNCE))
{
state->angles[0] = ent->v->v_angle[0]/-3.0;
state->angles[1] = ent->v->v_angle[1];
state->angles[2] = ent->v->v_angle[2];
}
}
if (client && client->edict && (ent->v->owner == client->edict->entnum))

View File

@ -1608,7 +1608,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
{
eval_t *eval;
eval = PR_FindGlobal(svprogfuncs, "startspot", 0, NULL);
if (eval) eval->string = PR_NewString(svprogfuncs, startspot, 0);
if (eval) eval->string = PR_NewString(svprogfuncs, startspot);
}
if (Cmd_AliasExist("f_svnewmap", RESTRICT_LOCAL))

View File

@ -126,6 +126,7 @@ cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0");
cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat");
cvar_t pausable = CVAR("pausable", "1");
cvar_t sv_banproxies = CVARD("sv_banproxies", "0", "If enabled, anyone connecting via known proxy software will be refused entry. This should aid with blocking aimbots, but is only reliable for certain public proxies.");
cvar_t sv_specprint = CVARD("sv_specprint", "3", "Bitfield that controls which player events spectators see when tracking that player.\n&1: spectators will see centerprints.\n&2: spectators will see sprints (pickup messages etc).\n&4: spectators will receive console commands, this is potentially risky.\nIndividual spectators can use 'setinfo sp foo' to limit this setting.");
//
@ -1706,6 +1707,9 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
int maxpacketentities;
extern cvar_t pr_maxedicts;
client->fteprotocolextensions &= Net_PextMask(1, ISNQCLIENT(client));
client->fteprotocolextensions2 &= Net_PextMask(2, ISNQCLIENT(client));
//some gamecode can't cope with some extensions for some reasons... and I'm too lazy to fix the code to cope.
if (svs.gametype == GT_HALFLIFE)
client->fteprotocolextensions2 &= ~PEXT2_REPLACEMENTDELTAS;
@ -4498,6 +4502,7 @@ void SV_InitLocal (void)
Cvar_Register (&sv_csqc_progname, cvargroup_servercontrol);
Cvar_Register (&sv_csqcdebug, cvargroup_servercontrol);
Cvar_Register (&sv_specprint, cvargroup_serverpermissions);
Cvar_Register (&sv_gamespeed, cvargroup_serverphysics);
Cvar_Register (&sv_nqplayerphysics, cvargroup_serverphysics);
@ -4550,9 +4555,10 @@ void SV_InitLocal (void)
}
#define iswhite(c) ((c) == ' ' || (unsigned char)(c) == (unsigned char)INVIS_CHAR1 || (unsigned char)(c) == (unsigned char)INVIS_CHAR2 || (unsigned char)(c) == (unsigned char)INVIS_CHAR3)
#define isinvalid(c) ((c) == ':' || (c) == '\r' || (c) == '\n' || (unsigned char)(c) == (unsigned char)0xff)
#define isinvalid(c) ((c) == ':' || (c) == '\r' || (c) == '\n' || (unsigned char)(c) == (unsigned char)0xff || (c) == '\"')
//colon is so clients can't get confused while parsing chats
//255 is so fuhquake/ezquake don't end up with nameless players
//" is so mods that use player names in tokenizing/frik_files don't mess up. mods are still expected to be able to cope with space.
//is allowed to shorten, out must be as long as in and min of "unnamed"+1
void SV_FixupName(char *in, char *out, unsigned int outlen)
@ -4811,6 +4817,12 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
cl->messagelevel = atoi(val);
}
val = Info_ValueForKey (cl->userinfo, "sp"); //naming for compat with mvdsv
if (*val)
cl->spec_print = atoi(val);
else
cl->spec_print = ~0; //if unspecified, default to server setting (even if the cvar is changed mid-map).
#ifdef NQPROT
{
int top = atoi(Info_ValueForKey(cl->userinfo, "topcolor"));

View File

@ -1646,8 +1646,9 @@ qboolean SV_MVD_Record (mvddest_t *dest)
}
else if (sv_demoExtensions.ival)
{ /*everything*/
extern cvar_t pext_replacementdeltas;
demo.recorder.fteprotocolextensions = PEXT_CSQC | PEXT_COLOURMOD | PEXT_DPFLAGS | PEXT_CUSTOMTEMPEFFECTS | PEXT_ENTITYDBL | PEXT_ENTITYDBL2 | PEXT_FATNESS | PEXT_HEXEN2 | PEXT_HULLSIZE | PEXT_LIGHTSTYLECOL | PEXT_MODELDBL | PEXT_SCALE | PEXT_SETATTACHMENT | PEXT_SETVIEW | PEXT_SOUNDDBL | PEXT_SPAWNSTATIC2 | PEXT_TRANS | PEXT_VIEW2;
demo.recorder.fteprotocolextensions2 = PEXT2_VOICECHAT | PEXT2_SETANGLEDELTA | PEXT2_PRYDONCURSOR | PEXT2_REPLACEMENTDELTAS;
demo.recorder.fteprotocolextensions2 = PEXT2_VOICECHAT | PEXT2_SETANGLEDELTA | PEXT2_PRYDONCURSOR | (pext_replacementdeltas.ival?PEXT2_REPLACEMENTDELTAS:0);
/*enable these, because we might as well (stat ones are always useful)*/
demo.recorder.zquake_extensions = Z_EXT_PM_TYPE | Z_EXT_PM_TYPE_NEW | Z_EXT_VIEWHEIGHT | Z_EXT_SERVERTIME | Z_EXT_PITCHLIMITS | Z_EXT_JOIN_OBSERVE | Z_EXT_VWEP;
}

View File

@ -2327,7 +2327,9 @@ void World_Physics_Frame(world_t *w)
sv_player = svs.clients[i-1].edict;
svs.clients[i-1].msecs = newt;
SV_PreRunCmd();
#ifndef NEWSPEEDCHEATPROT
svs.clients[i-1].last_check = 0;
#endif
svs.clients[i-1].lastcmd.msec = bound(0, delt, 255);
SV_RunCmd (&svs.clients[i-1].lastcmd, true);
svs.clients[i-1].lastcmd.impulse = 0;

View File

@ -297,7 +297,7 @@ void SV_TPrintToClient(client_t *cl, int level, const char *string)
SV_PrintToClient(cl, level, string);
}
void SV_StuffcmdToClient(client_t *cl, char *string)
void SV_StuffcmdToClient(client_t *cl, const char *string)
{
switch (cl->protocol)
{
@ -317,8 +317,29 @@ void SV_StuffcmdToClient(client_t *cl, char *string)
case SCP_NETQUAKE:
case SCP_PROQUAKE:
case SCP_FITZ666:
ClientReliableWrite_Begin (cl, svc_stufftext, strlen(string)+3);
ClientReliableWrite_String (cl, string);
if (cl->controller)
{ //this is a slave client.
//find the right number and send.
int pnum = 0;
client_t *sp;
for (sp = cl->controller; sp; sp = sp->controlled)
{
if (sp == cl)
break;
pnum++;
}
sp = cl->controller;
ClientReliableWrite_Begin (sp, svcfte_choosesplitclient, 4 + strlen(string));
ClientReliableWrite_Byte (sp, pnum);
ClientReliableWrite_Byte (sp, svc_stufftext);
ClientReliableWrite_String (sp, string);
}
else
{
ClientReliableWrite_Begin (cl, svc_stufftext, strlen(string)+3);
ClientReliableWrite_String (cl, string);
}
break;
}
}
@ -1227,6 +1248,8 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum)
for (i=0 ; i<3 ; i++)
MSG_WriteCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i]));
//FIXME: flood to spectators.
ent->v->dmg_take = 0;
ent->v->dmg_save = 0;
}
@ -1748,28 +1771,18 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf
{
statsf[STAT_HEALTH] = ent->v->health; //sorry, but mneh
statsi[STAT_WEAPON] = SV_ModelIndex(PR_GetString(svprogfuncs, ent->v->weaponmodel));
if (client->fteprotocolextensions & PEXT_MODELDBL)
{
if ((unsigned)statsi[STAT_WEAPON] >= MAX_PRECACHE_MODELS)
statsi[STAT_WEAPON] = 0;
}
else
{
if ((unsigned)statsi[STAT_WEAPON] >= 256)
statsi[STAT_WEAPON] = 0;
}
if ((unsigned)statsi[STAT_WEAPON] >= client->maxmodels)
statsi[STAT_WEAPON] = 0; //play it safe, try not to crash unsuspecting clients
statsf[STAT_AMMO] = ent->v->currentammo;
statsf[STAT_ARMOR] = ent->v->armorvalue;
statsf[STAT_SHELLS] = ent->v->ammo_shells;
statsf[STAT_NAILS] = ent->v->ammo_nails;
statsf[STAT_ROCKETS] = ent->v->ammo_rockets;
statsf[STAT_CELLS] = ent->v->ammo_cells;
if (!client->spectator)
{
statsf[STAT_ACTIVEWEAPON] = ent->v->weapon;
if ((client->csqcactive && !(client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) || client->protocol != SCP_QUAKEWORLD)
statsf[STAT_WEAPONFRAME] = ent->v->weaponframe;
}
statsf[STAT_ACTIVEWEAPON] = ent->v->weapon;
if ((client->csqcactive && !(client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) || client->protocol != SCP_QUAKEWORLD || (client->fteprotocolextensions2 & PEXT2_PREDINFO))
// if ((client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || client->protocol != SCP_QUAKEWORLD)
statsf[STAT_WEAPONFRAME] = ent->v->weaponframe; //weapon frame is sent differently with classic quakeworld protocols.
// stuff the sigil bits into the high bits of items for sbar
if (sv.haveitems2)
@ -1804,15 +1817,15 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf
statsfi[STAT_MOVEVARS_TIMESCALE] = sv_gamespeed.value;
statsfi[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
statsfi[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
statsfi[STAT_MOVEVARS_MAXSPEED] = host_client->maxspeed;
statsfi[STAT_MOVEVARS_MAXSPEED] = client->maxspeed;
statsfi[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_spectatormaxspeed.value;
statsfi[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
statsfi[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value;
statsfi[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value;
statsfi[STAT_MOVEVARS_ENTGRAVITY] = host_client->entgravity/sv_gravity.value;
statsfi[STAT_MOVEVARS_ENTGRAVITY] = client->entgravity/sv_gravity.value;
statsfi[STAT_MOVEVARS_JUMPVELOCITY] = 270;//sv_jumpvelocity.value; //bah
statsfi[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
statsfi[STAT_MOVEVARS_MAXAIRSPEED] = host_client->maxspeed;
statsfi[STAT_MOVEVARS_MAXAIRSPEED] = client->maxspeed;
statsfi[STAT_MOVEVARS_STEPHEIGHT] = 18;
statsfi[STAT_MOVEVARS_AIRACCEL_QW] = 1;
statsfi[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_gravity.value;
@ -1830,7 +1843,7 @@ Performs a delta update of the stats array. This should only be performed
when a reliable message can be delivered this frame.
=======================
*/
void SV_UpdateClientStats (client_t *client, int pnum)
void SV_UpdateClientStats (client_t *client, int pnum, sizebuf_t *msg, client_frame_t *frame)
{
int statsi[MAX_CL_STATS];
float statsf[MAX_CL_STATS];
@ -1844,6 +1857,124 @@ void SV_UpdateClientStats (client_t *client, int pnum)
if (client->fteprotocolextensions & (PEXT_HEXEN2|PEXT_CSQC))
m = MAX_CL_STATS;
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
//diff numerical stats first
for (i=0 ; i<m ; i++)
{
if (client->statsi[i] != statsi[i] || client->statsf[i] != statsf[i])
{
client->statsi[i] = statsi[i];
client->statsf[i] = statsf[i];
client->pendingstats[i>>5u] |= 1u<<(i&0x1f);
}
}
//diff string stats.
for (i=0 ; i<m ; i++)
{
char *blank="";
char *o=client->statss[i], *n=statss[i];
if (o != n)
{
if (!o)
o = "";
if (!n)
n = "";
if (strcmp(o, n))
client->pendingstats[(i+MAX_CL_STATS)>>5u] |= 1u<<((i+MAX_CL_STATS)&0x1f);
if (client->statss)
Z_Free(client->statss[i]);
client->statss[i] = Z_StrDup(statss[i]);
}
}
for (i=0 ; i<m ; i++)
{
if (client->pendingstats[i>>5u] & (1u<<(i&0x1f)))
{
float fval = client->statsf[i];
int ival = client->statsi[i];
//would overflow
if (msg->cursize+8 >= msg->maxsize)
break;
//can't track it
if (frame->numresendstats >= sizeof(frame->resendstats)/sizeof(frame->resendstats[0]))
break;
//we're going for it.
client->pendingstats[i>>5u] &= ~(1u<<(i&0x1f)); //doesn't need resending any more
frame->resendstats[frame->numresendstats++] = i | (pnum<<12);
if (fval && fval != (float)(int)fval && !dpcompat_stats.ival)
{
if (pnum)
{
MSG_WriteByte(msg, svcfte_choosesplitclient);
MSG_WriteByte(msg, pnum);
}
MSG_WriteByte(msg, svcfte_updatestatfloat);
MSG_WriteByte(msg, i);
MSG_WriteFloat(msg, fval);
}
else
{
if (fval)
ival = fval;
if (ival >= 0 && ival <= 255)
{
if (pnum)
{
MSG_WriteByte(msg, svcfte_choosesplitclient);
MSG_WriteByte(msg, pnum);
}
MSG_WriteByte(msg, svcqw_updatestatbyte);
MSG_WriteByte(msg, i);
MSG_WriteByte(msg, ival);
}
else
{
if (pnum)
{
MSG_WriteByte(msg, svcfte_choosesplitclient);
MSG_WriteByte(msg, pnum);
}
MSG_WriteByte(msg, svcqw_updatestatlong);
MSG_WriteByte(msg, i);
MSG_WriteLong(msg, ival);
}
}
}
}
for (i=0 ; i<m ; i++)
{
if (client->pendingstats[(i+MAX_CL_STATS)>>5u] & (1u<<((i+MAX_CL_STATS)&0x1f)))
{
char *s = client->statss[i];
if (!s)
s = "";
//would overflow
if (msg->cursize+4+strlen(s) >= msg->maxsize)
break;
//can't track it
if (frame->numresendstats >= sizeof(frame->resendstats)/sizeof(frame->resendstats[0]))
break;
//we're going for it.
client->pendingstats[(i+MAX_CL_STATS)>>5u] &= ~(1u<<((i+MAX_CL_STATS)&0x1f)); //doesn't need resending any more
frame->resendstats[frame->numresendstats++] = (i+MAX_CL_STATS) | (pnum<<12);
if (pnum)
{
MSG_WriteByte(msg, svcfte_choosesplitclient);
MSG_WriteByte(msg, pnum);
}
MSG_WriteByte(msg, svcfte_updatestatstring);
MSG_WriteByte(msg, i);
MSG_WriteString(msg, s);
}
}
}
else
for (i=0 ; i<m ; i++)
{
#ifdef SERVER_DEMO_PLAYBACK
@ -2020,7 +2151,14 @@ qboolean SV_SendClientDatagram (client_t *client)
{
qbyte buf[MAX_OVERALLMSGLEN];
sizebuf_t msg;
unsigned int sentbytes, fnum;
unsigned int sentbytes;
client_frame_t *frame = NULL;
if (ISQWCLIENT(client) || ISNQCLIENT(client))
{
frame = &client->frameunion.frames[client->netchan.outgoing_sequence & UPDATE_MASK];
frame->numresendstats = 0;
}
msg.data = buf;
msg.maxsize = sizeof(buf);
@ -2052,6 +2190,17 @@ qboolean SV_SendClientDatagram (client_t *client)
else
#endif
{
if (!ISQ2CLIENT(client) && Netchan_CanReliable (&client->netchan, SV_RateForClient(client)))
{
int pnum=1;
client_t *c;
SV_UpdateClientStats (client, 0, &msg, frame);
for (c = client->controlled; c; c = c->controlled,pnum++)
SV_UpdateClientStats(c, pnum, &msg, frame);
}
// add the client specific data to the datagram
SV_WriteClientdataToMessage (client, &msg);
@ -2073,18 +2222,6 @@ qboolean SV_SendClientDatagram (client_t *client)
SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
SZ_Clear (&client->datagram);
// send deltas over reliable stream
if (sv.world.worldmodel)
if (!ISQ2CLIENT(client) && Netchan_CanReliable (&client->netchan, SV_RateForClient(client)))
{
int pnum=1;
client_t *c;
SV_UpdateClientStats (client, 0);
for (c = client->controlled; c; c = c->controlled,pnum++)
SV_UpdateClientStats(c, pnum);
}
if (msg.overflowed)
{
Con_Printf ("WARNING: msg overflowed for %s\n", client->name);
@ -2094,11 +2231,10 @@ qboolean SV_SendClientDatagram (client_t *client)
SV_DarkPlacesDownloadChunk(client, &msg);
// send the datagram
fnum = client->netchan.outgoing_sequence;
sentbytes = Netchan_Transmit (&client->netchan, msg.cursize, buf, SV_RateForClient(client));
if (ISQWCLIENT(client) || ISNQCLIENT(client))
client->frameunion.frames[fnum & UPDATE_MASK].packetsizeout += sentbytes;
if (frame)
frame->packetsizeout += sentbytes;
return true;
}
@ -2240,7 +2376,9 @@ void SV_UpdateToReliableMessages (void)
}
name = PR_GetString(svprogfuncs, host_client->edict->v->netname);
#ifndef QCGC //this optimisation doesn't really work with a QC instead of static string management
if (name != host_client->name)
#endif
{
if (strcmp(host_client->name, name))
{
@ -2258,8 +2396,15 @@ void SV_UpdateToReliableMessages (void)
MSG_WriteString (&sv.reliable_datagram, "name");
MSG_WriteString (&sv.reliable_datagram, host_client->name);
}
#ifdef QCGC
//if it got rejected/mangled, make sure the qc properly sees the current value.
svprogfuncs->SetStringField(svprogfuncs, host_client->edict, &host_client->edict->v->netname, host_client->name, true);
#endif
}
host_client->edict->v->netname = PR_SetString(svprogfuncs, host_client->name);
#ifndef QCGC
svprogfuncs->SetStringField(svprogfuncs, host_client->edict, &host_client->edict->v->netname, host_client->name, true);
#endif
}
}
@ -2434,6 +2579,13 @@ void SV_SendClientMessages (void)
int sentbytes, fnum;
float pt = sv.paused?realtime:sv.world.physicstime;
#ifdef NEWSPEEDCHEATPROT
static unsigned int lasttime;
unsigned int curtime = Sys_Milliseconds();
unsigned int msecs = curtime - lasttime;
lasttime = curtime;
#endif
#ifdef Q3SERVER
if (svs.gametype == GT_QUAKE3)
{
@ -2496,6 +2648,34 @@ void SV_SendClientMessages (void)
continue;
}
#ifdef NEWSPEEDCHEATPROT
//allow the client more time for client movement.
//if they're running too slowly, FORCE them to run
//this little check is to guard against people using msecs=0 to hover in mid-air. also keeps players animating/moving/etc when timing
c->msecs += msecs;
while (c->msecs > 1000)
{
if (c->isindependant && !sv.paused)
{
usercmd_t cmd;
memset(&cmd, 0, sizeof(cmd));
host_client = c;
sv_player = c->edict;
SV_PreRunCmd();
cmd.msec = 50;
VectorCopy(c->lastcmd.angles, cmd.angles);
cmd.buttons = c->lastcmd.buttons;
SV_RunCmd (&cmd, true);
SV_PostRunCmd();
c->msecs -= 50;
host_client = NULL;
sv_player = NULL;
}
else
c->msecs = 500;
}
#endif
#ifdef Q3SERVER
if (ISQ3CLIENT(c))
{ //q3 protocols bypass backbuffering and pretty much everything else

View File

@ -1689,4 +1689,16 @@ qboolean Sys_RandomBytes(qbyte *string, int len)
CryptReleaseContext(prov, 0);
return true;
}
#ifdef HAVEAUTOUPDATE
int Sys_GetAutoUpdateSetting(void);
{
return -1;
}
void Sys_SetAutoUpdateSetting(int newval)
{
}
#endif
#endif

View File

@ -48,8 +48,10 @@ cvar_t sv_mapcheck = SCVAR("sv_mapcheck", "1");
cvar_t sv_fullredirect = CVARD("sv_fullredirect", "", "This is the ip:port to redirect players to when the server is full");
cvar_t sv_antilag = CVARFD("sv_antilag", "1", CVAR_SERVERINFO, "Attempt to backdate impacts to compensate for lag. 0=completely off. 1=mod-controlled. 2=forced, which might break certain uses of traceline.");
cvar_t sv_antilag_frac = CVARF("sv_antilag_frac", "1", CVAR_SERVERINFO);
#ifndef NEWSPEEDCHEATPROT
cvar_t sv_cheatpc = CVARD("sv_cheatpc", "125", "If the client tried to claim more than this percentage of time within any speed-cheat period, the client will be deemed to have cheated.");
cvar_t sv_cheatspeedchecktime = CVARD("sv_cheatspeedchecktime", "30", "The interval between each speed-cheat check.");
#endif
cvar_t sv_playermodelchecks = CVAR("sv_playermodelchecks", "0");
cvar_t sv_ping_ignorepl = CVARD("sv_ping_ignorepl", "0", "If 1, ping times reported for players will ignore the effects of packetloss on ping times. 0 is slightly more honest, but less useful for connection diagnosis.");
cvar_t sv_protocol_nq = CVARD("sv_protocol_nq", "0", "Specifies the default protocol to use for new NQ clients. Supported values are\n0 = autodetect\n15 = vanilla\n666 = fitzquake\n999 = rmq protocol\nThe sv_bigcoords cvar forces upgrades as required.");
@ -5866,12 +5868,19 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
vec3_t new_vel;
vec3_t old_vel;
// DMW copied this KK hack copied from QuakeForge anti-cheat
// (also extra inside parm on all SV_RunCmds that follow)
// To prevent a infinite loop
if (!recurse)
{
#ifdef NEWSPEEDCHEATPROT
if (ucmd->msec && host_client->msecs > 500)
host_client->msecs = 500;
if (ucmd->msec > host_client->msecs)
return;
host_client->msecs -= ucmd->msec;
#else
// DMW copied this KK hack copied from QuakeForge anti-cheat
// (also extra inside parm on all SV_RunCmds that follow)
//FIXME: update protocol to use server's timestamps instead of msecs over the wire, obsoleting speed cheat checks (by allowing the server to clamp sanely).
if (!host_client->last_check)
@ -5905,9 +5914,10 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
host_client->msecs = 0;
host_client->last_check = realtime;
}
// end KK hack copied from QuakeForge anti-cheat
//it's amazing how code get's copied around...
#endif
}
// end KK hack copied from QuakeForge anti-cheat
//it's amazing how code get's copied around...
if (SV_RunFullQCMovement(host_client, ucmd))
{
@ -6056,13 +6066,22 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
// show 1/3 the pitch angle and all the roll angle
if (sv_player->v->health > 0)
{
if (!sv_player->v->fixangle)
if (sv_player->v->movetype == MOVETYPE_6DOF)
{
sv_player->v->angles[PITCH] = -sv_player->v->v_angle[PITCH]/3;
sv_player->v->angles[PITCH] = -sv_player->v->v_angle[PITCH];
sv_player->v->angles[YAW] = sv_player->v->v_angle[YAW];
sv_player->v->angles[ROLL] = sv_player->v->v_angle[ROLL];
}
else
{
if (!sv_player->v->fixangle)
{
sv_player->v->angles[PITCH] = -sv_player->v->v_angle[PITCH]/3;
sv_player->v->angles[YAW] = sv_player->v->v_angle[YAW];
}
sv_player->v->angles[ROLL] =
V_CalcRoll (sv_player->v->angles, sv_player->v->velocity)*4;
}
sv_player->v->angles[ROLL] =
V_CalcRoll (sv_player->v->angles, sv_player->v->velocity)*4;
}
if (SV_PlayerPhysicsQC && !host_client->spectator)
@ -7331,8 +7350,10 @@ void SV_UserInit (void)
Cvar_Register (&sv_fullredirect, cvargroup_servercontrol);
Cvar_Register (&sv_antilag, cvargroup_servercontrol);
Cvar_Register (&sv_antilag_frac, cvargroup_servercontrol);
#ifndef NEWSPEEDCHEATPROT
Cvar_Register (&sv_cheatpc, cvargroup_servercontrol);
Cvar_Register (&sv_cheatspeedchecktime, cvargroup_servercontrol);
#endif
Cvar_Register (&sv_playermodelchecks, cvargroup_servercontrol);
Cvar_Register (&sv_getrealip, cvargroup_servercontrol);

View File

@ -13,7 +13,7 @@ attribute vec2 v_texcoord;
void main ()
{
tc = v_texcoord;
gl_Position = v_position;
gl_Position = vec4(v_position, 1.0);
}
#endif
#ifdef FRAGMENT_SHADER
@ -30,6 +30,7 @@ void main()
vec2 textCoo = tc.st;
deltaTextCoord *= 1.0 / float(NUM_SAMPLES) * crep_density;
float illuminationDecay = 1.0;
gl_FragColor = vec4(0.0,0.0,0.0,0.0);
for(int i=0; i < NUM_SAMPLES ; i++)
{
textCoo -= deltaTextCoord;

View File

@ -31,6 +31,12 @@ struct v2f
SamplerState SampleType;
float4 main (v2f inp) : SV_TARGET
{
return shaderTexture.Sample(SampleType, inp.tc) * inp.vcol;
float4 tex = shaderTexture.Sample(SampleType, inp.tc);
#ifdef MASK
if (tex.a < float(MASK))
discard;
#endif
//FIXME: no fog, no colourmod
return tex * inp.vcol;
}
#endif

View File

@ -486,13 +486,13 @@ LONG WINAPI MainWndProc (
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
// if (!vid_initializing)
INS_TranslateKeyEvent(wParam, lParam, true, 0);
INS_TranslateKeyEvent(wParam, lParam, true, 0, false);
break;
case WM_KEYUP:
case WM_SYSKEYUP:
// if (!vid_initializing)
INS_TranslateKeyEvent(wParam, lParam, false, 0);
INS_TranslateKeyEvent(wParam, lParam, false, 0, false);
break;
// this is complicated because Win32 seems to pack multiple mouse events into