From 347311db8c9fdeb9fddc620315cfacc959ca0590 Mon Sep 17 00:00:00 2001 From: Spoike Date: Thu, 8 Sep 2005 22:52:46 +0000 Subject: [PATCH] q3 fixes and misilaneous minor changes. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@1298 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_cg.c | 109 +++- engine/client/cl_ents.c | 2 +- engine/client/cl_screen.c | 2 +- engine/client/cl_tent.c | 4 +- engine/client/cl_ui.c | 79 ++- engine/client/clq3_parse.c | 13 +- engine/client/clq3defs.h | 1 + engine/client/m_download.c | 5 +- engine/client/pr_menu.c | 11 +- engine/client/r_part.c | 100 ++-- engine/client/sys_win.c | 14 +- engine/client/valid.c | 38 +- engine/common/cmd.c | 39 +- engine/common/common.c | 4 +- engine/common/crc.c | 18 +- engine/common/crc.h | 8 +- engine/common/fs.c | 4 +- engine/common/gl_q2bsp.c | 19 + engine/common/particles.h | 2 +- engine/common/q1bsp.c | 72 ++- engine/common/q3common.c | 28 +- engine/common/ui_public.h | 271 +++++---- engine/common/zone.c | 7 + engine/gl/gl_alias.c | 2 +- engine/gl/gl_backend.c | 161 +++++- engine/gl/gl_draw.c | 21 +- engine/gl/gl_hlmdl.c | 4 +- engine/gl/gl_model.c | 9 +- engine/gl/gl_ppl.c | 15 +- engine/gl/gl_rlight.c | 2 +- engine/gl/gl_rmain.c | 6 +- engine/gl/gl_screen.c | 1 + engine/gl/ltface.c | 6 +- engine/http/httpclient.c | 4 +- engine/http/iwebiface.c | 2 +- engine/qclib/comprout.c | 5 + engine/qclib/qcc.h | 1 - engine/qclib/qcc_pr_comp.c | 16 +- engine/qclib/qcc_pr_lex.c | 6 +- engine/qclib/qcdecomp.c | 121 +++-- engine/server/pr_cmds.c | 5 +- engine/server/q3g_public.h | 141 +++-- engine/server/sv_init.c | 10 +- engine/server/sv_main.c | 32 +- engine/server/svq3_game.c | 1058 ++++++++++++++++++++++++++++++++++-- engine/sw/sw_draw.c | 2 +- engine/sw/sw_model.c | 12 +- 47 files changed, 2015 insertions(+), 477 deletions(-) diff --git a/engine/client/cl_cg.c b/engine/client/cl_cg.c index 0f046c64..e5233b76 100644 --- a/engine/client/cl_cg.c +++ b/engine/client/cl_cg.c @@ -336,7 +336,7 @@ qboolean CGQ3_GetUserCmd(int cmdNumber, q3usercmd_t *ucmd) static vm_t *cgvm; -static int keycatcher; +extern int keycatcher; qboolean CG_GetServerCommand(int cmdnum) { @@ -344,7 +344,7 @@ qboolean CG_GetServerCommand(int cmdnum) // get the gamestate from the client system, which will have the // new configstring already integrated - char *str = ccs.serverCommands[cmdnum % TEXTCMD_MASK]; + char *str = ccs.serverCommands[cmdnum & TEXTCMD_MASK]; Con_DPrintf("Dispaching %s\n", str); Cmd_TokenizeString(str, false, false); @@ -355,6 +355,71 @@ qboolean CG_GetServerCommand(int cmdnum) } +typedef struct { + int firstPoint; + int numPoints; +} markFragment_t; +int CG_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, + int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) +{ +#if 1 //FIXME: make work + return 0; +#else + vec3_t center; + vec3_t axis[3]; + vec3_t p[4]; + int i; + float radius; + + if (numPoints != 4) + return 0; + + /* + q3 gamecode includes something like this + + originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i]; + originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i]; + originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i]; + originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i]; + + We want that origional axis and the origin + axis[0] is given in the 'projection' parameter. + + Yes, reversing this stuff means that we'll have no support for triangles. + */ + + VectorClear(center); + VectorAdd(center, points[0], center); + VectorAdd(center, points[1], center); + VectorAdd(center, points[2], center); + VectorAdd(center, points[3], center); + + VectorSubtract(points[0], center, p[0]); + VectorSubtract(points[1], center, p[1]); + VectorSubtract(points[2], center, p[2]); + VectorSubtract(points[3], center, p[3]); + + for (i = 0; i < 3; i++) + { + axis[1][i] = (p[2][i]+p[1][i])/2; + axis[2][i] = (p[2][i]+p[3][i])/2; + } + + radius = VectorNormalize(axis[1]); + VectorNormalize(axis[2]); + VectorNormalize(projection); + + + + + Q1BSP_ClipDecal(center, axis[0], axis[1], axis[2], radius, pointBuffer, maxPoints); + fragmentBuffer->firstPoint = 0; + fragmentBuffer->numPoints = 0; + + return 1; +#endif +} + void GLDraw_Image(float x, float y, float w, float h, float s1, float t1, float s2, float t2, qpic_t *pic); int VM_LerpTag(void *out, model_t *model, int f1, int f2, float l2, char *tagname); @@ -464,7 +529,7 @@ static long CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const long Cbuf_AddText(VM_POINTER(arg[0]), RESTRICT_SERVER); break; case CG_ADDCOMMAND: - Cmd_AddRemCommand(VM_POINTER(arg[0]), CG_Command_f); + Cmd_AddRemCommand(VM_POINTER(arg[0]), NULL); break; case CG_SENDCLIENTCOMMAND: Con_DPrintf("CG_SENDCLIENTCOMMAND: %s", VM_POINTER(arg[0])); @@ -472,8 +537,11 @@ static long CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const long break; case CG_UPDATESCREEN: //force a buffer swap cos loading won't refresh it soon. - GL_EndRendering(); - GL_DoSwap(); + SCR_BeginLoadingPlaque(); + SCR_UpdateScreen(); + SCR_EndLoadingPlaque(); +// GL_EndRendering(); +// GL_DoSwap(); break; case CG_FS_FOPENFILE: //fopen @@ -499,10 +567,10 @@ static long CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const long if (!mod) mod = cl.worldmodel; if (mod) - pc = mod->funcs.PointContents(mod, VM_POINTER(arg[0])); + pc = CM_PointContents(mod, VM_POINTER(arg[0])); else - pc = FTECONTENTS_SOLID; - VM_LONG(ret) = Contents_To_Q3(pc); + pc = 1;//FTECONTENTS_SOLID; + VM_LONG(ret) = pc;//Contents_To_Q3(pc); } break; @@ -537,11 +605,11 @@ static long CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const long } if (mod) - pc = mod->funcs.PointContents(mod, p_l); + pc = CM_PointContents(mod, p_l); else - pc = FTECONTENTS_SOLID; + pc = 1;//FTECONTENTS_SOLID; } - VM_LONG(ret) = Contents_To_Q3(pc); + VM_LONG(ret) = pc;//Contents_To_Q3(pc); } break; @@ -705,6 +773,18 @@ static long CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const long case CG_R_CLEARSCENE: //clear scene cl_numvisedicts=0; + { + int i; + for (i = 0; i < MAX_DLIGHTS; i++) + { + if (cl_dlights[i].isstatic) + continue; + cl_dlights[i].radius = 0; + } + } + break; + case CG_R_ADDPOLYTOSCENE: + // ... break; case CG_R_ADDREFENTITYTOSCENE: //add ent to scene VQ3_AddEntity(VM_POINTER(arg[0])); @@ -717,6 +797,7 @@ static long CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const long } break; case CG_R_RENDERSCENE: //render scene + GLR_PushDlights(); VQ3_RenderView(VM_POINTER(arg[0])); break; @@ -817,6 +898,7 @@ static long CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const long break; case CG_CM_MARKFRAGMENTS: + VM_LONG(ret) = CG_MarkFragments( VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3]), VM_POINTER(arg[4]), VM_LONG(arg[5]), VM_POINTER(arg[6]) ); break; case CG_GETCURRENTSNAPSHOTNUMBER: @@ -925,7 +1007,7 @@ static long CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const long UI_RegisterFont(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_POINTER(arg[2])); break; default: - Con_Printf("Q3CG: Bad system trap: %d\n", fn); + Host_EndGame("Q3CG: Bad system trap: %d\n", fn); } return ret; @@ -1020,14 +1102,17 @@ void CG_Start (void) } Z_FreeTags(CGTAGNUM); + SCR_BeginLoadingPlaque(); cgvm = VM_Create(NULL, "vm/cgame", CG_SystemCalls, CG_SystemCallsEx); if (cgvm) { //hu... cgame doesn't appear to have a query version call! VM_Call(cgvm, CG_INIT, ccs.serverMessageNum, ccs.lastServerCommandNum, cl.playernum[0]); + SCR_EndLoadingPlaque(); } else { + SCR_EndLoadingPlaque(); Host_EndGame("Failed to initialise cgame module\n"); } #endif diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 27a8dc4d..bcd2f4e1 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -1557,7 +1557,7 @@ void CL_LinkPacketEntities (void) model = cl.model_precache[s1->modelindex]; if (!model) { - Con_DPrintf("Bad modelindex\n"); + Con_DPrintf("Bad modelindex (%i)\n", s1->modelindex); continue; } diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 76e7ae1f..df8728cb 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1165,7 +1165,7 @@ void SCR_DrawLoading (void) void SCR_BeginLoadingPlaque (void) { - if (cls.state != ca_active) + if (cls.state != ca_active && cls.protocol != CP_QUAKE3) return; if (!scr_initialized) diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 35a0929a..13d390e7 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -344,7 +344,7 @@ void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ n switch(tent) { case 0: - if (ent < 0 && ent >= -MAX_CLIENTS) //a zquake concept. ent between -1 and -maxplayers is to be taken to be a railtrail from a particular player instead of a beam. + if (ent < 0 && ent >= -512) //a zquake concept. ent between -1 and -maxplayers is to be taken to be a railtrail from a particular player instead of a beam. { CLQ2_RailTrail(start, end); return; @@ -401,7 +401,7 @@ void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ n } } - if (cl_beam_trace.value && etype >= 0 && cls.state == ca_active) + if (cl_beam_trace.value && etype >= 0 && cls.state == ca_active && P_TypeIsLoaded(etype)) { VectorSubtract(end, start, normal); VectorNormalize(normal); diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 7b0b445f..b17fcac4 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -3,6 +3,8 @@ #include "ui_public.h" #include "cl_master.h" +int keycatcher; + #ifdef VM_UI #include "clq3defs.h" @@ -202,8 +204,6 @@ static char *scr_centerstring; static int ox, oy; -static int keycatcher; - void GLDraw_Image(float x, float y, float w, float h, float s1, float t1, float s2, float t2, qpic_t *pic); void SWDraw_Image (float xp, float yp, float wp, float hp, float s1, float t1, float s2, float t2, qpic_t *pic); char *Get_Q2ConfigString(int i); @@ -454,6 +454,30 @@ int VMEnumMods(char *match, int size, void *args) return true; } +int VMQ3_GetFileList(char *path, char *ext, char *output, int buffersize) +{ + vmsearch_t vms; + vms.initialbuffer = vms.buffer = output; + vms.skip = strlen(path)+1; + vms.bufferleft = buffersize; + vms.found=0; + if (*(char *)path == '$') + { + extern char com_basedir[]; + vms.skip=0; + Sys_EnumerateFiles(com_basedir, "*", VMEnumMods, &vms); + } + else if (*(char *)ext == '.' || *(char *)ext == '/') + COM_EnumerateFiles(va("%s/*%s", path, ext), VMEnum, &vms); + else + COM_EnumerateFiles(va("%s/*.%s", path, ext), VMEnum, &vms); + return vms.found; +} + + + + + typedef struct q3refEntity_s { refEntityType_t reType; int renderfx; @@ -731,7 +755,7 @@ long UI_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) //make sure that any called functions are also range checked. //like reading from files copies names into alternate buffers, allowing stack screwups. - switch((ui_builtinnum_t)fn) + switch((uiImport_t)fn) { case UI_ERROR: Con_Printf("%s", VM_POINTER(arg[0])); @@ -744,6 +768,19 @@ long UI_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) VM_LONG(ret) = Sys_Milliseconds(); break; + case UI_ARGC: + VM_LONG(ret) = Cmd_Argc(); + break; + case UI_ARGV: +// VALIDATEPOINTER(arg[1], arg[2]); + Q_strncpyz(VM_POINTER(arg[1]), Cmd_Argv(VM_LONG(arg[0])), VM_LONG(arg[2])); + break; +/* case UI_ARGS: + VALIDATEPOINTER(arg[0], arg[1]); + Q_strncpyz(VM_POINTER(arg[0]), Cmd_Args(), VM_LONG(arg[1])); + break; +*/ + case UI_CVAR_SET: { cvar_t *var; @@ -849,25 +886,7 @@ long UI_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) case UI_FS_GETFILELIST: //fs listing if ((int)arg[2] + arg[3] >= mask || VM_POINTER(arg[2]) < offset) break; //out of bounds. - { - vmsearch_t vms; - vms.initialbuffer = vms.buffer = VM_POINTER(arg[2]); - vms.skip = strlen(VM_POINTER(arg[0]))+1; - vms.bufferleft = arg[3]; - vms.found=0; - if (*(char *)VM_POINTER(arg[0]) == '$') - { - extern char com_basedir[]; - vms.skip=0; - Sys_EnumerateFiles(com_basedir, "*", VMEnumMods, &vms); - } - else if (*(char *)VM_POINTER(arg[1]) == '.' || *(char *)VM_POINTER(arg[1]) == '/') - COM_EnumerateFiles(va("%s/*%s", VM_POINTER(arg[0]), VM_POINTER(arg[1])), VMEnum, &vms); - else - COM_EnumerateFiles(va("%s/*.%s", VM_POINTER(arg[0]), VM_POINTER(arg[1])), VMEnum, &vms); - VM_LONG(ret) = vms.found; - } - break; + return VMQ3_GetFileList(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); case UI_R_REGISTERMODEL: //precache model { @@ -951,6 +970,9 @@ long UI_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) S_LocalSound(VM_LONG(arg[0])+(char *)offset); break; + case UI_KEY_GETOVERSTRIKEMODE: + return true; + case UI_KEY_KEYNUMTOSTRINGBUF: if (VM_LONG(arg[0]) < 0 || VM_LONG(arg[0]) > 255 || (int)arg[1] + VM_LONG(arg[2]) >= mask || VM_POINTER(arg[1]) < offset || VM_LONG(arg[2]) < 1) break; //out of bounds. @@ -1529,8 +1551,8 @@ void UI_MousePosition(int xpos, int ypos) ypos = vid.height; ox=0;oy=0; //force a cap - VM_Call(uivm, UI_MOUSE_DELTA, -32767, -32767); - VM_Call(uivm, UI_MOUSE_DELTA, (xpos-ox)*640/vid.width, (ypos-oy)*480/vid.height); + VM_Call(uivm, UI_MOUSE_EVENT, -32767, -32767); + VM_Call(uivm, UI_MOUSE_EVENT, (xpos-ox)*640/vid.width, (ypos-oy)*480/vid.height); ox = xpos; oy = ypos; @@ -1573,7 +1595,7 @@ void UI_Start (void) } VM_Call(uivm, UI_INIT); - VM_Call(uivm, UI_MOUSE_DELTA, -32767, -32767); + VM_Call(uivm, UI_MOUSE_EVENT, -32767, -32767); ox = 0; oy = 0; @@ -1595,6 +1617,13 @@ void UI_Restart_f(void) } } +qboolean UI_Command(void) +{ + if (uivm) + return VM_Call(uivm, UI_CONSOLE_COMMAND); + return false; +} + void UI_Init (void) { Cmd_AddRemCommand("ui_restart", UI_Restart_f); diff --git a/engine/client/clq3_parse.c b/engine/client/clq3_parse.c index d0ef676e..e7f10d9d 100644 --- a/engine/client/clq3_parse.c +++ b/engine/client/clq3_parse.c @@ -261,7 +261,7 @@ void CLQ3_ParseSnapshot(void) snap.serverMessageNum = ccs.serverMessageNum; snap.serverCommandNum = ccs.lastServerCommandNum; snap.serverTime = MSG_ReadLong(); - snap.localTime = Sys_DoubleTime()*1000; + snap.localTime = Sys_Milliseconds(); // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of @@ -862,6 +862,7 @@ void CLQ3_SendCmd(usercmd_t *cmd) frame_t *frame, *oldframe; int cmdcount, key; usercmd_t *to, *from; + extern int keycatcher; if (cls.resendinfo) { @@ -869,7 +870,7 @@ void CLQ3_SendCmd(usercmd_t *cmd) CLQ3_SendClientCommand("userinfo \"%s\"", cls.userinfo); } - ccs.serverTime = ccs.snap.serverTime + (Sys_Milliseconds()-ccs.snap.localTime); + cl.gametime = ccs.serverTime = ccs.snap.serverTime + (Sys_Milliseconds()-ccs.snap.localTime); //reuse the q1 array cmd->servertime = ccs.serverTime; @@ -879,6 +880,14 @@ void CLQ3_SendCmd(usercmd_t *cmd) cmd->sidemove *= 127/400.0f; cmd->upmove *= 127/400.0f; + if (cmd->buttons & 2) //jump + { + cmd->upmove = 100; + cmd->buttons &= ~2; + } + if (key_dest != key_game || (keycatcher&3)) + cmd->buttons |= 2; //add in the 'at console' button + cl.frames[ccs.currentUserCmdNumber&CMD_MASK].cmd[0] = *cmd; ccs.currentUserCmdNumber++; diff --git a/engine/client/clq3defs.h b/engine/client/clq3defs.h index 21c266df..257f24eb 100644 --- a/engine/client/clq3defs.h +++ b/engine/client/clq3defs.h @@ -148,6 +148,7 @@ typedef struct q3entityState_s { int torsoAnim; // mask off ANIM_TOGGLEBIT int generic1; + } q3entityState_t; #define MAX_MAP_AREA_BYTES 32 diff --git a/engine/client/m_download.c b/engine/client/m_download.c index a2575c77..d1b02fdd 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -182,7 +182,7 @@ void ConcatPackageLists(package_t *l2) static void dlnotification(char *localfile, qboolean sucess) { FILE *f; - + FS_FlushFSHash(); COM_FOpenFile(localfile, &f); if (f) { @@ -315,7 +315,8 @@ qboolean M_Download_Key (struct menucustom_s *c, struct menu_s *m, int key) { if ((p->flags&DPF_WANTTOINSTALL) && !(p->flags&DPF_HAVEAVERSION)) { //if we want it and don't have it: - if (HTTP_CL_Get(p->src, va("../%s", p->dest), NULL)) + COM_CreatePath(va("%s/%s", com_gamedir, p->dest)); + if (HTTP_CL_Get(p->src, p->dest, NULL)) p->flags|=DPF_HAVEAVERSION; //FIXME: This is error prone. } } diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 3ccb721b..81a39df0 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -1293,7 +1293,16 @@ void MP_Shutdown (void) func_t temp; if (!menuprogs) return; - +/* + { + char *buffer; + int size = 1024*1024*8; + buffer = Z_Malloc(size); + menuprogs->save_ents(menuprogs, buffer, &size, 1); + COM_WriteFile("menucore.txt", buffer, size); + Z_Free(buffer); + } +*/ temp = mp_shutdown_function; mp_shutdown_function = 0; if (temp && !inmenuprogs) diff --git a/engine/client/r_part.c b/engine/client/r_part.c index c8852690..0262a079 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -154,6 +154,25 @@ typedef struct { float rotation; } ramp_t; +#define APPLYBLEND(bm) \ + switch (bm) \ + { \ + case BM_ADD: \ + qglBlendFunc(GL_SRC_ALPHA, GL_ONE); \ + break; \ + case BM_SUBTRACT: \ + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR); \ + break; \ + case BM_BLENDCOLOUR: \ + qglBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR); \ + break; \ + case BM_BLEND: \ + default: \ + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); \ + break; \ + } + + typedef struct part_type_s { char name[MAX_QPATH]; char texname[MAX_QPATH]; @@ -309,6 +328,18 @@ int P_DescriptionIsLoaded(char *name) return i+1; } +qboolean P_TypeIsLoaded(int effect) +{ + int i = effect; + part_type_t *ptype; + if (i < 0) + return false; + ptype = &part_type[i]; + if (!ptype->loaded) + return false; + return true; +} + static void P_SetModified(void) //called when the particle system changes (from console). { if (Cmd_FromGamecode()) @@ -649,9 +680,10 @@ void P_ParticleEffect_f(void) ptype->blendmode = BM_ADD; else if (!strcmp(value, "subtract")) ptype->blendmode = BM_SUBTRACT; + else if (!strcmp(value, "blendcolour") || !strcmp(value, "blendcolor")) + ptype->blendmode = BM_BLENDCOLOUR; else - ptype->blendmode = BM_MERGE; - + ptype->blendmode = BM_BLEND; } else if (!strcmp(var, "spawnmode")) { @@ -1932,10 +1964,8 @@ int P_RunParticleEffectState (vec3_t org, vec3_t dir, float count, int typenum, } } dir = bestdir; - dir[0]*=-1; - dir[1]*=-1; - dir[2]*=-1; } + VectorInverse(dir); VectorNormalize(vec); CrossProduct(dir, vec, tangent); @@ -3089,12 +3119,7 @@ void GL_DrawTexturedParticle(particle_t *p, part_type_t *type) qglEnd(); qglEnable(GL_TEXTURE_2D); GL_Bind(type->texturenum); - if (type->blendmode == BM_ADD) //addative - qglBlendFunc(GL_SRC_ALPHA, GL_ONE); -// else if (type->blendmode == BM_SUBTRACT) //subtractive -// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - else - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + APPLYBLEND(type->blendmode); qglShadeModel(GL_FLAT); qglBegin(GL_QUADS); } @@ -3199,12 +3224,7 @@ void GL_DrawTrifanParticle(particle_t *p, part_type_t *type) { lasttype = type; qglDisable(GL_TEXTURE_2D); - if (type->blendmode == BM_ADD) //addative - qglBlendFunc(GL_SRC_ALPHA, GL_ONE); -// else if (type->blendmode == BM_SUBTRACT) //subtractive -// qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - else - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + APPLYBLEND(type->blendmode); qglShadeModel(GL_SMOOTH); } @@ -3248,12 +3268,7 @@ void GL_DrawLineSparkParticle(particle_t *p, part_type_t *type) qglEnd(); qglDisable(GL_TEXTURE_2D); GL_Bind(type->texturenum); - if (type->blendmode == BM_ADD) //addative - qglBlendFunc(GL_SRC_ALPHA, GL_ONE); -// else if (type->blendmode == BM_SUBTRACT) //subtractive -// qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - else - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + APPLYBLEND(type->blendmode); qglShadeModel(GL_SMOOTH); qglBegin(GL_LINES); } @@ -3280,12 +3295,7 @@ void GL_DrawTexturedSparkParticle(particle_t *p, part_type_t *type) qglEnd(); qglEnable(GL_TEXTURE_2D); GL_Bind(type->texturenum); - if (type->blendmode == BM_ADD) //addative - qglBlendFunc(GL_SRC_ALPHA, GL_ONE); -// else if (type->blendmode == BM_SUBTRACT) //subtractive -// qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - else - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + APPLYBLEND(type->blendmode); qglShadeModel(GL_SMOOTH); qglBegin(GL_QUADS); } @@ -3329,12 +3339,7 @@ void GL_DrawSketchSparkParticle(particle_t *p, part_type_t *type) qglEnd(); qglDisable(GL_TEXTURE_2D); GL_Bind(type->texturenum); - if (type->blendmode == BM_ADD) //addative - qglBlendFunc(GL_SRC_ALPHA, GL_ONE); -// else if (type->blendmode == BM_SUBTRACT) //subtractive -// qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - else - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + APPLYBLEND(type->blendmode); qglShadeModel(GL_SMOOTH); qglBegin(GL_LINES); } @@ -3380,12 +3385,7 @@ void GL_DrawParticleBeam_Textured(beamseg_t *b, part_type_t *type) qglEnd(); qglEnable(GL_TEXTURE_2D); GL_Bind(type->texturenum); - if (type->blendmode == BM_ADD) //addative - qglBlendFunc(GL_SRC_ALPHA, GL_ONE); -// else if (type->blendmode == BM_SUBTRACT) //subtractive -// qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - else - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + APPLYBLEND(type->blendmode); qglShadeModel(GL_SMOOTH); qglBegin(GL_QUADS); } @@ -3454,12 +3454,7 @@ void GL_DrawParticleBeam_Untextured(beamseg_t *b, part_type_t *type) qglEnd(); qglDisable(GL_TEXTURE_2D); GL_Bind(type->texturenum); - if (type->blendmode == BM_ADD) //addative - qglBlendFunc(GL_SRC_ALPHA, GL_ONE); -// else if (type->blendmode == BM_SUBTRACT) //subtractive -// qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - else - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + APPLYBLEND(type->blendmode); qglShadeModel(GL_SMOOTH); qglBegin(GL_QUADS); } @@ -3545,13 +3540,12 @@ void GL_DrawClippedDecal(clippeddecal_t *d, part_type_t *type) qglEnd(); qglEnable(GL_TEXTURE_2D); GL_Bind(type->texturenum); - if (type->blendmode == BM_ADD) //addative - qglBlendFunc(GL_SRC_ALPHA, GL_ONE); -// else if (type->blendmode == BM_SUBTRACT) //subtractive -// qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - else - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + APPLYBLEND(type->blendmode); qglShadeModel(GL_SMOOTH); + +// qglDisable(GL_TEXTURE_2D); +// qglBegin(GL_LINE_LOOP); + qglBegin(GL_TRIANGLES); } diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 2d3f7afd..3d551aed 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -957,6 +957,14 @@ HWND hwnd_dialog; qboolean isDedicated = false; #endif +#include +void Signal_Error_Handler(int i) +{ + int *basepointer; + __asm {mov basepointer,ebp}; + Sys_Error("Receieved signal, offset was 0x%8x", basepointer[73]); +} + int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // MSG msg; @@ -969,7 +977,11 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin /* previous instances do not exist in Win32 */ if (hPrevInstance) - return 0; + return 0; + + signal (SIGFPE, Signal_Error_Handler); + signal (SIGILL, Signal_Error_Handler); + signal (SIGSEGV, Signal_Error_Handler); global_hInstance = hInstance; global_nCmdShow = nCmdShow; diff --git a/engine/client/valid.c b/engine/client/valid.c index 6cfab74c..3f266280 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -39,10 +39,10 @@ cvar_t allow_f_skins = {"allow_f_skins", "1"}; cvar_t auth_validateclients = {"auth_validateclients", "1"}; -void CRC_AddBlock (unsigned short *crcvalue, qbyte *start, int count) +void QCRC_AddBlock (unsigned short *crcvalue, qbyte *start, int count) { while (count--) - CRC_ProcessByte(crcvalue, *start++); + QCRC_ProcessByte(crcvalue, *start++); } unsigned short SCRC_GetQueryStateCrc(char *f_query_string) { @@ -50,41 +50,41 @@ unsigned short SCRC_GetQueryStateCrc(char *f_query_string) int i; char *tmp; - CRC_Init(&crc); + QCRC_Init(&crc); // add query - CRC_AddBlock(&crc, f_query_string, strlen(f_query_string)); + QCRC_AddBlock(&crc, f_query_string, strlen(f_query_string)); // add snapshot of serverinfo - tmp = Info_ValueForKey(cl.serverinfo, "deathmatch"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "teamplay"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); - tmp = Info_ValueForKey(cl.serverinfo, "hostname"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "deathmatch"); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "teamplay"); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); + tmp = Info_ValueForKey(cl.serverinfo, "hostname"); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); tmp = Info_ValueForKey(cl.serverinfo, "*progs"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); tmp = Info_ValueForKey(cl.serverinfo, "map"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); tmp = Info_ValueForKey(cl.serverinfo, "spawn"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); tmp = Info_ValueForKey(cl.serverinfo, "watervis"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); tmp = Info_ValueForKey(cl.serverinfo, "fraglimit"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); tmp = Info_ValueForKey(cl.serverinfo, "*gamedir"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); tmp = Info_ValueForKey(cl.serverinfo, "timelimit"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); // add snapshot of userinfo for every connected client for (i=0; i < MAX_CLIENTS; i++) if (cl.players[i].name[0]) { tmp = Info_ValueForKey(cl.players[i].userinfo, "name"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); tmp = Info_ValueForKey(cl.players[i].userinfo, "team"); - CRC_AddBlock(&crc, tmp, strlen(tmp)); + QCRC_AddBlock(&crc, tmp, strlen(tmp)); } // done diff --git a/engine/common/cmd.c b/engine/common/cmd.c index beec6883..0d2ba94a 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -1645,7 +1645,21 @@ void Cmd_ExecuteString (char *text, int level) if ((cmd->restriction?cmd->restriction:rcon_level.value) > level) Con_TPrintf(TL_WASRESTIRCTED, cmd_argv[0]); else if (!cmd->function) + { +#ifdef VM_CG + if (CG_Command()) + return; +#endif +#ifdef Q3SERVER + if (SVQ3_Command()) + return; +#endif +#ifdef VM_UI + if (UI_Command()) + return; +#endif Cmd_ForwardToServer (); + } else cmd->function (); return; @@ -1737,8 +1751,16 @@ void Cmd_ExecuteString (char *text, int level) if (CG_Command()) return; #endif +#ifdef Q3SERVER + if (SVQ3_Command()) + return; +#endif +#ifdef VM_UI + if (UI_Command()) + return; +#endif #ifdef Q2CLIENT - if (cls.protocol == CP_QUAKE2) + if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) { //q2 servers convert unknown commands to text. Cmd_ForwardToServer(); return; @@ -2235,6 +2257,20 @@ skipblock: If_Token_Clear(ts); } +void Cmd_Vstr_f( void ) +{ + char *v; + + if (Cmd_Argc () != 2) + { + Con_Printf ("vstr : execute a variable command\n"); + return; + } + + v = Cvar_VariableString(Cmd_Argv(1)); + Cbuf_InsertText(va("%s\n", v), Cmd_ExecLevel); +} + void Cmd_set_f(void) { cvar_t *var; @@ -2717,6 +2753,7 @@ void Cmd_Init (void) Cmd_AddCommand ("set", Cmd_set_f); Cmd_AddCommand ("seta", Cmd_set_f); + Cmd_AddCommand ("vstr", Cmd_Vstr_f); Cmd_AddCommand ("inc", Cvar_Inc_f); //FIXME: Add seta some time. Cmd_AddCommand ("if", Cmd_if_f); diff --git a/engine/common/common.c b/engine/common/common.c index 456ec23c..fd0d01dd 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2792,7 +2792,7 @@ qbyte COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence) length += 4; - crc = CRC_Block(chkb, length); + crc = QCRC_Block(chkb, length); crc &= 0xff; @@ -2900,7 +2900,7 @@ qbyte Q2COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence) length += 4; - crc = CRC_Block(chkb, length); + crc = QCRC_Block(chkb, length); for (x=0, n=0; n> 8) ^ data]; } -unsigned short CRC_Value(unsigned short crcvalue) +unsigned short QCRC_Value(unsigned short crcvalue) { - return crcvalue ^ CRC_XOR_VALUE; + return crcvalue ^ QCRC_XOR_VALUE; } -unsigned short CRC_Block (qbyte *start, int count) +unsigned short QCRC_Block (qbyte *start, int count) { unsigned short crc; - CRC_Init (&crc); + QCRC_Init (&crc); while (count--) crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++]; diff --git a/engine/common/crc.h b/engine/common/crc.h index 71fbe7bd..7db046fc 100644 --- a/engine/common/crc.h +++ b/engine/common/crc.h @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* crc.h */ -void CRC_Init(unsigned short *crcvalue); -void CRC_ProcessByte(unsigned short *crcvalue, qbyte data); -unsigned short CRC_Value(unsigned short crcvalue); -unsigned short CRC_Block (qbyte *start, int count); +void QCRC_Init(unsigned short *crcvalue); +void QCRC_ProcessByte(unsigned short *crcvalue, qbyte data); +unsigned short QCRC_Value(unsigned short crcvalue); +unsigned short QCRC_Block (qbyte *start, int count); diff --git a/engine/common/fs.c b/engine/common/fs.c index 8d9e3541..1b8710f0 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -363,10 +363,10 @@ void *FSPAK_LoadPackFile (char *packfile) // fread (&info, 1, header.dirlen, packhandle); // crc the directory to check for modifications -// crc = CRC_Block((qbyte *)info, header.dirlen); +// crc = QCRC_Block((qbyte *)info, header.dirlen); -// CRC_Init (&crc); +// QCRC_Init (&crc); pack = (pack_t*)Z_Malloc (sizeof (pack_t)); // parse the directory diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 9be64929..6e8f53cf 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -3294,7 +3294,24 @@ void Q2BSP_MarkLights (dlight_t *light, int bit, mnode_t *node) int i; if (node->contents != -1) + { + mleaf_t *leaf = (mleaf_t *)node; + msurface_t **mark; + + i = leaf->nummarksurfaces; + mark = leaf->firstmarksurface; + while(i--!=0) + { + surf = *mark++; + if (surf->dlightframe != r_dlightframecount) + { + surf->dlightbits = 0; + surf->dlightframe = r_dlightframecount; + } + surf->dlightbits |= bit; + } return; + } splitplane = node->plane; dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; @@ -3769,6 +3786,7 @@ q2cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned + loadmodel->checksum = loadmodel->checksum2 = *checksum; loadmodel->numsubmodels = CM_NumInlineModels(loadmodel); @@ -3925,6 +3943,7 @@ void CM_InitBoxHull (void) #endif box_model.funcs.LeafPVS = CM_LeafnumPVS; box_model.funcs.LeafnumForPoint = CM_PointLeafnum; + box_model.funcs.Trace = CM_Trace; box_model.hulls[0].available = true; Q2BSP_SetHullFuncs(&box_model.hulls[0]); diff --git a/engine/common/particles.h b/engine/common/particles.h index a7b07d75..1f628401 100644 --- a/engine/common/particles.h +++ b/engine/common/particles.h @@ -181,6 +181,6 @@ void P_EmitSkyEffectTris(struct model_s *mod, struct msurface_s *fa); // trailstate functions void P_DelinkTrailstate(trailstate_t **tsk); -typedef enum { BM_MERGE, BM_ADD, BM_SUBTRACT } blendmode_t; +typedef enum { BM_BLEND, BM_BLENDCOLOUR, BM_ADD, BM_SUBTRACT } blendmode_t; #endif diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index f3660663..608f5971 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -333,11 +333,12 @@ typedef struct { vec3_t center; vec3_t normal; - vec3_t tangent1; - vec3_t tangent2; +// vec3_t tangent1; +// vec3_t tangent2; vec3_t planenorm[6]; float planedist[6]; + int numplanes; vec_t radius; int numtris; @@ -527,11 +528,12 @@ int Fragment_ClipPolyToPlane(float *inverts, float *outverts, int incount, float float *lastvalid = NULL; //the reason these arn't just an index is because it'd need to be a special case for the first vert. float lastvaliddot = 0; +#define FRAG_EPSILON 0.5 for (i = 0; i < incount; i++) { dotv[i] = DotProduct((inverts+i*3), plane) - planedist; - if (dotv[i]<-DIST_EPSILON) + if (dotv[i]<-FRAG_EPSILON) clippedcount++; else { @@ -543,14 +545,25 @@ int Fragment_ClipPolyToPlane(float *inverts, float *outverts, int incount, float if (clippedcount == incount) return 0; //all were clipped if (clippedcount == 0) - { + { //none were clipped memcpy(outverts, inverts, sizeof(float)*3*incount); return incount; } + //FIXME: +/* + + We should end up with a nicly clipped quad. + If a vertex is on the other side of the place, we remove it, and add two in it's place, on the lines between the verts not chopped. + we work out the last remaining vert in the above loop + the loop below loops through all verts, if it's to be removed, it does a nested loop to find the next vert that is not going to be removed + it then adds two new verts on the right two lines. + Due to using four clipplanes, this should result in a perfect quad. It doesn't. + +*/ for (i = 0; i < incount; ) { - if (dotv[i] < -DIST_EPSILON) //clipped + if (dotv[i] < -FRAG_EPSILON) //clipped { //work out where the line impacts the plane lastvaliddot = (dotv[i]) / (dotv[i]-lastvaliddot); @@ -559,20 +572,25 @@ int Fragment_ClipPolyToPlane(float *inverts, float *outverts, int incount, float if (outcount+1 >= MAXFRAGMENTVERTS) //bum break; + //generate a vertex where the line crosses the plane outverts[outcount*3 + 0] = impact[0]; outverts[outcount*3 + 1] = impact[1]; outverts[outcount*3 + 2] = impact[2]; outcount++; i3 = (i+1); - while (dotv[i3%incount] < -DIST_EPSILON) //clipped + while (dotv[i3%incount] < -FRAG_EPSILON) //clipped i3++; + + //take away any verticies on the other side of the plane + i = (i3-1)%incount; i2=i3%incount; lastvaliddot = (dotv[i]) / (dotv[i]-dotv[i2]); VectorInterpolate((inverts+i*3), lastvaliddot, (inverts+i2*3), impact); + //generate a vertex where the line crosses back onto our plane outverts[outcount*3 + 0] = impact[0]; outverts[outcount*3 + 1] = impact[1]; outverts[outcount*3 + 2] = impact[2]; @@ -608,7 +626,9 @@ void Fragment_ClipTriangle(fragmentdecal_t *dec, float *a, float *b, float *c) int p; float verts[MAXFRAGMENTVERTS*3]; float verts2[MAXFRAGMENTVERTS*3]; + float *cverts; int numverts; + int flip; if (dec->numtris == MAXFRAGMENTTRIS) @@ -620,17 +640,24 @@ void Fragment_ClipTriangle(fragmentdecal_t *dec, float *a, float *b, float *c) numverts = 3; //clip the triangle to the 6 planes. - for (p = 0; p < 6; p+=2) + flip = 0; + for (p = 0; p < dec->numplanes; p++) { - numverts = Fragment_ClipPolyToPlane(verts, verts2, numverts, dec->planenorm[p], dec->planedist[p]); - if (numverts < 3) //totally clipped. - return; + flip^=1; + if (flip) + numverts = Fragment_ClipPolyToPlane(verts, verts2, numverts, dec->planenorm[p], dec->planedist[p]); + else + numverts = Fragment_ClipPolyToPlane(verts2, verts, numverts, dec->planenorm[p], dec->planedist[p]); - numverts = Fragment_ClipPolyToPlane(verts2, verts, numverts, dec->planenorm[p+1], dec->planedist[p+1]); if (numverts < 3) //totally clipped. return; } + if (flip) + cverts = verts2; + else + cverts = verts; + //decompose the resultant polygon into triangles. while(numverts>2) @@ -640,9 +667,9 @@ void Fragment_ClipTriangle(fragmentdecal_t *dec, float *a, float *b, float *c) numverts--; - VectorCopy((verts+3*0), decalfragmentverts[dec->numtris*3+0]); - VectorCopy((verts+3*(numverts-1)), decalfragmentverts[dec->numtris*3+1]); - VectorCopy((verts+3*numverts), decalfragmentverts[dec->numtris*3+2]); + VectorCopy((cverts+3*0), decalfragmentverts[dec->numtris*3+0]); + VectorCopy((cverts+3*(numverts-1)), decalfragmentverts[dec->numtris*3+1]); + VectorCopy((cverts+3*numverts), decalfragmentverts[dec->numtris*3+2]); dec->numtris++; } } @@ -650,7 +677,7 @@ void Fragment_ClipTriangle(fragmentdecal_t *dec, float *a, float *b, float *c) #endif //this could be inlined, but I'm lazy. -void Q1BSP_FragmentToMesh (fragmentdecal_t *dec, mesh_t *mesh) +void Fragment_Mesh (fragmentdecal_t *dec, mesh_t *mesh) { int i; @@ -707,33 +734,32 @@ void Q1BSP_ClipDecalToNodes (fragmentdecal_t *dec, mnode_t *node) if (DotProduct(surf->plane->normal, dec->normal) > -0.5) continue; } - Q1BSP_FragmentToMesh(dec, surf->mesh); + Fragment_Mesh(dec, surf->mesh); } Q1BSP_ClipDecalToNodes (dec, node->children[0]); Q1BSP_ClipDecalToNodes (dec, node->children[1]); } -int Q1BSP_ClipDecal(vec3_t center, vec3_t normal, vec3_t tangent, vec3_t tangent2, float size, float **out) +int Q1BSP_ClipDecal(vec3_t center, vec3_t normal, vec3_t tangent1, vec3_t tangent2, float size, float **out) { //quad marks a full, independant quad int p; fragmentdecal_t dec; VectorCopy(center, dec.center); VectorCopy(normal, dec.normal); - VectorCopy(tangent, dec.tangent1); - VectorCopy(tangent2, dec.tangent2); dec.radius = size/2; dec.numtris = 0; - VectorCopy(dec.tangent1, dec.planenorm[0]); - VectorNegate(dec.tangent1, dec.planenorm[1]); - VectorCopy(dec.tangent2, dec.planenorm[2]); - VectorNegate(dec.tangent2, dec.planenorm[3]); + VectorCopy(tangent1, dec.planenorm[0]); + VectorNegate(tangent1, dec.planenorm[1]); + VectorCopy(tangent2, dec.planenorm[2]); + VectorNegate(tangent2, dec.planenorm[3]); VectorCopy(dec.normal, dec.planenorm[4]); VectorNegate(dec.normal, dec.planenorm[5]); for (p = 0; p < 6; p++) dec.planedist[p] = -(dec.radius - DotProduct(dec.center, dec.planenorm[p])); + dec.numplanes = 6; Q1BSP_ClipDecalToNodes(&dec, cl.worldmodel->nodes); diff --git a/engine/common/q3common.c b/engine/common/q3common.c index 8fe61b3e..c5a5cf08 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -240,7 +240,7 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) if (chan->drop_count > 0)// && (net_showdrop->integer || net_showpackets->integer)) { - Con_Printf("%s:Dropped %i packets at %i\n", NET_AdrToString(chan->remote_address), chan->drop_count, sequence); + Con_DPrintf("%s:Dropped %i packets at %i\n", NET_AdrToString(chan->remote_address), chan->drop_count, sequence); } if (!fragment) @@ -467,7 +467,7 @@ int StringKey( const char *string, int length ) key += string[i] * (119 + i); } - return (((key >> 10) ^ key) >> 10) ^ key; + return (key ^ (key >> 10) ^ (key >> 20)); } @@ -1281,10 +1281,21 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * //////////////////////////////////////////////////////////// //user commands +int kbitmask[32] = { + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFf, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, +}; + static int MSG_ReadDeltaKey(int key, int from, int bits) { if (MSG_ReadBits(1)) - return MSG_ReadBits(bits)^key; + return MSG_ReadBits(bits)^ (key & kbitmask[bits]); else return from; } @@ -1296,7 +1307,16 @@ void MSG_Q3_ReadDeltaUsercmd(int key, const usercmd_t *from, usercmd_t *to) to->servertime = MSG_ReadBits(32); if (!MSG_ReadBits(1)) - memcpy((qbyte *)to+4, (qbyte *)from+4, sizeof(usercmd_t)-4); + { + to->angles[0] = from->angles[0]; + to->angles[1] = from->angles[1]; + to->angles[2] = from->angles[2]; + to->forwardmove = from->forwardmove; + to->sidemove = from->sidemove; + to->upmove = from->upmove; + to->buttons = from->buttons; + to->weapon = from->weapon; + } else { key ^= to->servertime; diff --git a/engine/common/ui_public.h b/engine/common/ui_public.h index 1547fa26..465920eb 100644 --- a/engine/common/ui_public.h +++ b/engine/common/ui_public.h @@ -1,3 +1,26 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + + //these structures are shared with the exe. #define UIMAX_SCOREBOARDNAME 16 @@ -49,24 +72,61 @@ typedef enum { //q2's config strings come here. } stringid_e; +typedef enum { + Q3CA_UNINITIALIZED, + Q3CA_DISCONNECTED, // not talking to a server + Q3CA_AUTHORIZING, // not used any more, was checking cd key + Q3CA_CONNECTING, // sending request packets to the server + Q3CA_CHALLENGING, // sending challenge packets to the server + Q3CA_CONNECTED, // netchan_t established, getting gamestate + Q3CA_LOADING, // only during cgame initialization, never during main loop + Q3CA_PRIMED, // got gamestate, waiting for first frame + Q3CA_ACTIVE, // game views should be displayed + Q3CA_CINEMATIC // playing a cinematic or a static pic, not connected to a server +} q3connstate_t; +typedef struct { + q3connstate_t connState; + int connectPacketCount; + int clientNum; + char servername[MAX_STRING_CHARS]; + char updateInfoString[MAX_STRING_CHARS]; + char messageString[MAX_STRING_CHARS]; +} uiClientState_t; + #define UI_API_VERSION 5000 typedef enum { - UI_GETAPIVERSION = 0, - UI_INIT = 1, - UI_SHUTDOWN = 2, - UI_KEY_EVENT = 3, - UI_MOUSE_DELTA = 4, - UI_REFRESH = 5, - UI_IS_FULLSCREEN = 6, - UI_SET_ACTIVE_MENU = 7, - UI_CONSOLE_COMMAND = 8, - UI_DRAW_CONNECT_SCREEN = 9, - UI_HASUNIQUECDKEY = 10, - //return value expected - //0 means don't take input - //1 means engine should skip map/scrback update, - //2 means fade the screen or draw console back. (expected to be most used) - //3 means don't fade the screen + UI_GETAPIVERSION = 0, // system reserved + + UI_INIT, +// void UI_Init( void ); + + UI_SHUTDOWN, +// void UI_Shutdown( void ); + + UI_KEY_EVENT, +// void UI_KeyEvent( int key ); + + UI_MOUSE_EVENT, +// void UI_MouseEvent( int dx, int dy ); + + UI_REFRESH, +// void UI_Refresh( int time ); + + UI_IS_FULLSCREEN, +// qboolean UI_IsFullscreen( void ); + + UI_SET_ACTIVE_MENU, +// void UI_SetActiveMenu( uiMenuCommand_t menu ); + + UI_CONSOLE_COMMAND, +// qboolean UI_ConsoleCommand( int realTime ); + + UI_DRAW_CONNECT_SCREEN, +// void UI_DrawConnectScreen( qboolean overlay ); + UI_HASUNIQUECDKEY, +// if !overlay, the background will be drawn, otherwise it will be +// overlayed over whatever the cgame has drawn. +// a GetClientState syscall will be made to get the current strings UI_DRAWSTATUSBAR = 500, UI_MOUSE_POS, @@ -77,95 +137,95 @@ typedef enum { } uiExport_t; typedef enum { - UI_ERROR = 0, - UI_PRINT = 1, - UI_MILLISECONDS = 2, - UI_CVAR_SET = 3, - UI_CVAR_VARIABLEVALUE = 4, - UI_CVAR_VARIABLESTRINGBUFFER = 5, - UI_CVAR_SETVALUE = 6, - UI_CVAR_RESET = 7, - UI_CVAR_CREATE = 8, - UI_CVAR_INFOSTRINGBUFFER = 9, - UI_ARGC = 10, - UI_ARGV = 11, - UI_CMD_EXECUTETEXT = 12, - UI_FS_FOPENFILE = 13, - UI_FS_READ = 14, - UI_FS_WRITE = 15, - UI_FS_FCLOSEFILE = 16, - UI_FS_GETFILELIST = 17, - UI_R_REGISTERMODEL = 18, - UI_R_REGISTERSKIN = 19, - UI_R_REGISTERSHADERNOMIP = 20, - UI_R_CLEARSCENE = 21, - UI_R_ADDREFENTITYTOSCENE = 22, - UI_R_ADDPOLYTOSCENE = 23, - UI_R_ADDLIGHTTOSCENE = 24, - UI_R_RENDERSCENE = 25, - UI_R_SETCOLOR = 26, - UI_R_DRAWSTRETCHPIC = 27, - UI_UPDATESCREEN = 28, - UI_CM_LERPTAG = 29, - UI_CM_LOADMODEL = 30, - UI_S_REGISTERSOUND = 31, - UI_S_STARTLOCALSOUND = 32, - UI_KEY_KEYNUMTOSTRINGBUF = 33, - UI_KEY_GETBINDINGBUF = 34, - UI_KEY_SETBINDING = 35, - UI_KEY_ISDOWN = 36, - UI_KEY_GETOVERSTRIKEMODE = 37, - UI_KEY_SETOVERSTRIKEMODE = 38, - UI_KEY_CLEARSTATES = 39, - UI_KEY_GETCATCHER = 40, - UI_KEY_SETCATCHER = 41, - UI_GETCLIPBOARDDATA = 42, - UI_GETGLCONFIG = 43, - UI_GETCLIENTSTATE = 44, - UI_GETCONFIGSTRING = 45, - UI_LAN_GETPINGQUEUECOUNT = 46, - UI_LAN_CLEARPING = 47, - UI_LAN_GETPING = 48, - UI_LAN_GETPINGINFO = 49, - UI_CVAR_REGISTER = 50, - UI_CVAR_UPDATE = 51, - UI_MEMORY_REMAINING = 52, - UI_GET_CDKEY = 53, - UI_SET_CDKEY = 54, - UI_R_REGISTERFONT = 55, - UI_R_MODELBOUNDS = 56, - UI_PC_ADD_GLOBAL_DEFINE = 57, - UI_PC_LOAD_SOURCE = 58, - UI_PC_FREE_SOURCE = 59, - UI_PC_READ_TOKEN = 60, - UI_PC_SOURCE_FILE_AND_LINE = 61, - UI_S_STOPBACKGROUNDTRACK = 62, - UI_S_STARTBACKGROUNDTRACK = 63, - UI_REAL_TIME = 64, - UI_LAN_GETSERVERCOUNT = 65, - UI_LAN_GETSERVERADDRESSSTRING = 66, - UI_LAN_GETSERVERINFO = 67, - UI_LAN_MARKSERVERVISIBLE = 68, - UI_LAN_UPDATEVISIBLEPINGS = 69, - UI_LAN_RESETPINGS = 70, - UI_LAN_LOADCACHEDSERVERS = 71, - UI_LAN_SAVECACHEDSERVERS = 72, - UI_LAN_ADDSERVER = 73, - UI_LAN_REMOVESERVER = 74, - UI_CIN_PLAYCINEMATIC = 75, - UI_CIN_STOPCINEMATIC = 76, - UI_CIN_RUNCINEMATIC = 77, - UI_CIN_DRAWCINEMATIC = 78, - UI_CIN_SETEXTENTS = 79, - UI_R_REMAP_SHADER = 80, - UI_VERIFY_CDKEY = 81, - UI_LAN_SERVERSTATUS = 82, - UI_LAN_GETSERVERPING = 83, - UI_LAN_SERVERISVISIBLE = 84, - UI_LAN_COMPARESERVERS = 85, + UI_ERROR, + UI_PRINT, + UI_MILLISECONDS, + UI_CVAR_SET, + UI_CVAR_VARIABLEVALUE, + UI_CVAR_VARIABLESTRINGBUFFER, + UI_CVAR_SETVALUE, + UI_CVAR_RESET, + UI_CVAR_CREATE, + UI_CVAR_INFOSTRINGBUFFER, + UI_ARGC, + UI_ARGV, + UI_CMD_EXECUTETEXT, + UI_FS_FOPENFILE, + UI_FS_READ, + UI_FS_WRITE, + UI_FS_FCLOSEFILE, + UI_FS_GETFILELIST, + UI_R_REGISTERMODEL, + UI_R_REGISTERSKIN, + UI_R_REGISTERSHADERNOMIP, + UI_R_CLEARSCENE, + UI_R_ADDREFENTITYTOSCENE, + UI_R_ADDPOLYTOSCENE, + UI_R_ADDLIGHTTOSCENE, + UI_R_RENDERSCENE, + UI_R_SETCOLOR, + UI_R_DRAWSTRETCHPIC, + UI_UPDATESCREEN, + UI_CM_LERPTAG, + UI_CM_LOADMODEL, + UI_S_REGISTERSOUND, + UI_S_STARTLOCALSOUND, + UI_KEY_KEYNUMTOSTRINGBUF, + UI_KEY_GETBINDINGBUF, + UI_KEY_SETBINDING, + UI_KEY_ISDOWN, + UI_KEY_GETOVERSTRIKEMODE, + UI_KEY_SETOVERSTRIKEMODE, + UI_KEY_CLEARSTATES, + UI_KEY_GETCATCHER, + UI_KEY_SETCATCHER, + UI_GETCLIPBOARDDATA, + UI_GETGLCONFIG, + UI_GETCLIENTSTATE, + UI_GETCONFIGSTRING, + UI_LAN_GETPINGQUEUECOUNT, + UI_LAN_CLEARPING, + UI_LAN_GETPING, + UI_LAN_GETPINGINFO, + UI_CVAR_REGISTER, + UI_CVAR_UPDATE, + UI_MEMORY_REMAINING, + UI_GET_CDKEY, + UI_SET_CDKEY, + UI_R_REGISTERFONT, + UI_R_MODELBOUNDS, + UI_PC_ADD_GLOBAL_DEFINE, + UI_PC_LOAD_SOURCE, + UI_PC_FREE_SOURCE, + UI_PC_READ_TOKEN, + UI_PC_SOURCE_FILE_AND_LINE, + UI_S_STOPBACKGROUNDTRACK, + UI_S_STARTBACKGROUNDTRACK, + UI_REAL_TIME, + UI_LAN_GETSERVERCOUNT, + UI_LAN_GETSERVERADDRESSSTRING, + UI_LAN_GETSERVERINFO, + UI_LAN_MARKSERVERVISIBLE, + UI_LAN_UPDATEVISIBLEPINGS, + UI_LAN_RESETPINGS, + UI_LAN_LOADCACHEDSERVERS, + UI_LAN_SAVECACHEDSERVERS, + UI_LAN_ADDSERVER, + UI_LAN_REMOVESERVER, + UI_CIN_PLAYCINEMATIC, + UI_CIN_STOPCINEMATIC, + UI_CIN_RUNCINEMATIC, + UI_CIN_DRAWCINEMATIC, + UI_CIN_SETEXTENTS, + UI_R_REMAP_SHADER, + UI_VERIFY_CDKEY, + UI_LAN_SERVERSTATUS, + UI_LAN_GETSERVERPING, + UI_LAN_SERVERISVISIBLE, + UI_LAN_COMPARESERVERS, // 1.32 - UI_FS_SEEK = 86, - UI_SET_PBCLSTATUS = 87, + UI_FS_SEEK, + UI_SET_PBCLSTATUS, UI_MEMSET = 100, UI_MEMCPY, @@ -177,7 +237,6 @@ typedef enum { UI_FLOOR, UI_CEIL, - UI_CACHE_PIC = 500, UI_PICFROMWAD = 501, UI_GETPLAYERINFO = 502, @@ -185,4 +244,4 @@ typedef enum { UI_GETVIDINFO = 504, UI_GET_STRING = 510, -} ui_builtinnum_t; +} uiImport_t; diff --git a/engine/common/zone.c b/engine/common/zone.c index e3c54b79..2229f9bc 100644 --- a/engine/common/zone.c +++ b/engine/common/zone.c @@ -151,6 +151,13 @@ int Z_Allocated(void) return used; } +int Z_MemSize(void *c) +{ + zone_t *nz; + nz = ((zone_t *)((char*)c-ZONEDEBUG))-1; + return nz->size; +} + void VARGS Z_Free (void *c) { zone_t *nz; diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index d9c68a77..d6f32631 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -2197,7 +2197,7 @@ void R_DrawMeshBumpmap(mesh_t *mesh, galiastexnum_t *skin, vec3_t lightdir) //so we use a cubemap, which has the added advantage of normalizing the light dir for us. //the bumpmap we use is tangent-space (so I'm told) - qglDepthFunc(GL_LEQUAL); + qglDepthFunc(gldepthfunc); qglDepthMask(0); if (gldepthmin == 0.5) qglCullFace ( GL_BACK ); diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index e405f8db..9036828b 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -274,6 +274,42 @@ unsigned int r_numtris; unsigned int r_numflushes; int r_backendStart; +int r_dlighttexture; + +void R_InitDynamicLightTexture (void) +{ + int x, y; + int dx2, dy, d; + qbyte data[64*64*4]; + + // + // dynamic light texture + // + + for (x = 0; x < 64; x++) + { + dx2 = x - 32; + dx2 = dx2 * dx2 + 8; + + for (y = 0; y < 64; y++) + { + dy = y - 32; + d = (int)(65536.0f * ((1.0f / (dx2 + dy * dy + 32.0f)) - 0.0005) + 0.5f); + if ( d < 50 ) d = 0; else if ( d > 255 ) d = 255; + + data[(y*64 + x) * 4 + 0] = d; + data[(y*64 + x) * 4 + 1] = d; + data[(y*64 + x) * 4 + 2] = d; + data[(y*64 + x) * 4 + 3] = 255; + } + } + + r_dlighttexture = GL_LoadTexture32("", 64, 64, (unsigned int*)data, true, false); + + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); +} + void R_ResetTexState (void) { coordsArray = inCoordsArray; @@ -494,6 +530,8 @@ void R_BackendInit (void) r_sawtoothtable[i] = t; r_inversesawtoothtable[i] = 1.0 - t; } + + R_InitDynamicLightTexture(); } qboolean varrayactive; @@ -2211,6 +2249,118 @@ void R_DrawNormals (void) qglEnable( GL_TEXTURE_2D ); } +/* +================= +R_AddDynamicLights +================= +*/ +void R_AddDynamicLights ( meshbuffer_t *mb ) +{ + dlight_t *light; + int i, j, lnum; + vec3_t point, tvec, dlorigin; + vec3_t vright, vup; + vec3_t dir1, dir2, normal, right, up, oldnormal; + float *v[3], dist, scale; + index_t *oldIndexesArray, index[3]; + int dlightNumIndexes, oldNumIndexes; + + oldNumIndexes = numIndexes; + oldIndexesArray = indexesArray; + VectorClear ( oldnormal ); + + GL_Bind ( r_dlighttexture ); + + qglDepthFunc ( GL_EQUAL ); + qglBlendFunc ( GL_DST_COLOR, GL_ONE ); + GL_TexEnv(GL_MODULATE); + + light = cl_dlights; + for ( lnum = 0; lnum < 32; lnum++, light++ ) + { + if ( !(mb->dlightbits & (1<radius) + continue; //urm + + VectorSubtract ( light->origin, currententity->origin, dlorigin ); + if ( !Matrix3_Compare (currententity->axis, axisDefault) ) + { + VectorCopy ( dlorigin, point ); + Matrix3_Multiply_Vec3 ( currententity->axis, point, dlorigin ); + } + + qglColor4f (light->color[0]*2, light->color[1]*2, light->color[2]*2, + 1);//light->color[3]); + + R_ResetTexState (); + dlightNumIndexes = 0; + + for ( i = 0; i < oldNumIndexes; i += 3 ) + { + index[0] = oldIndexesArray[i+0]; + index[1] = oldIndexesArray[i+1]; + index[2] = oldIndexesArray[i+2]; + + v[0] = (float *)(vertexArray + index[0]); + v[1] = (float *)(vertexArray + index[1]); + v[2] = (float *)(vertexArray + index[2]); + + // calculate two mostly perpendicular edge directions + VectorSubtract ( v[0], v[1], dir1 ); + VectorSubtract ( v[2], v[1], dir2 ); + + // we have two edge directions, we can calculate a third vector from + // them, which is the direction of the surface normal + CrossProduct ( dir1, dir2, normal ); + VectorNormalize ( normal ); + + VectorSubtract ( v[0], dlorigin, tvec ); + dist = DotProduct ( tvec, normal ); + if ( dist < 0 ) + dist = -dist; + if ( dist >= light->radius ) { + continue; + } + + VectorMA ( dlorigin, -dist, normal, point ); + scale = 1 / (light->radius - dist); + + if ( !VectorCompare (normal, oldnormal) ) { + MakeNormalVectors ( normal, right, up ); + VectorCopy ( normal, oldnormal ); + } + + VectorScale ( right, scale, vright ); + VectorScale ( up, scale, vup ); + + for ( j = 0; j < 3; j++ ) + { + // Get our texture coordinates + // Project the light image onto the face + VectorSubtract( v[j], point, tvec ); + + coordsArray[index[j]][0] = DotProduct( tvec, vright ) + 0.5f; + coordsArray[index[j]][1] = DotProduct( tvec, vup ) + 0.5f; + } + + tempIndexesArray[dlightNumIndexes++] = index[0]; + tempIndexesArray[dlightNumIndexes++] = index[1]; + tempIndexesArray[dlightNumIndexes++] = index[2]; + } + + if ( dlightNumIndexes ) { + R_PushIndexes ( tempIndexesArray, NULL, NULL, dlightNumIndexes, MF_NONBATCHED ); + R_FlushArrays (); + dlightNumIndexes = 0; + } + } + + numIndexes = oldNumIndexes; + indexesArray = oldIndexesArray; +} + + /* ================ R_FinishMeshBuffer @@ -2236,12 +2386,13 @@ void R_FinishMeshBuffer ( meshbuffer_t *mb ) qglDisable ( GL_ALPHA_TEST ); qglDepthMask ( GL_FALSE ); -//FIZME -// if ( dlight ) { -// R_AddDynamicLights ( mb ); -// } + if (dlight && (currententity->model->type == mod_brush && currententity->model->fromgame == fg_quake3)) //HACK: the extra check is because we play with the lightmaps in q1/q2 + { + R_AddDynamicLights ( mb ); + } - if ( fogged ) { + if (fogged) + { R_RenderFogOnMesh ( shader, mb->fog ); } } diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 07d9778a..22756a80 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -742,7 +742,7 @@ TRACE(("dbg: GLDraw_ReInit: Allocating upload buffers\n")); // add ocrana leds if (con_ocranaleds.value) { - if (con_ocranaleds.value != 2 || CRC_Block(draw_chars, 128*128) == 798) + if (con_ocranaleds.value != 2 || QCRC_Block(draw_chars, 128*128) == 798) AddOcranaLEDsIndexed (draw_chars, 128, 128); } @@ -1088,12 +1088,12 @@ void GLDraw_Init (void) memset(scrap_allocated, 0, sizeof(scrap_allocated)); - R_BackendInit(); - Cmd_AddRemCommand ("gl_texturemode", &GLDraw_TextureMode_f); GLDraw_ReInit(); + R_BackendInit(); + draw_mesh.numindexes = 6; @@ -1554,11 +1554,16 @@ void GLDraw_ShaderImage (int x, int y, int w, int h, float s1, float t1, float s */ draw_mesh.colors_array = draw_mesh_colors; - R_PushMesh(&draw_mesh, mb.shader->features | MF_COLORS | MF_NONBATCHED); - R_RenderMeshBuffer ( &mb, false ); - draw_mesh.colors_array = NULL; - - qglEnable(GL_BLEND); + __try + { + R_PushMesh(&draw_mesh, mb.shader->features | MF_COLORS | MF_NONBATCHED); + R_RenderMeshBuffer ( &mb, false ); + draw_mesh.colors_array = NULL; + qglEnable(GL_BLEND); + } __except(EXCEPTION_EXECUTE_HANDLER) + { + return; + }; } #endif diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index 683e2768..feb2112d 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -102,9 +102,9 @@ void Mod_LoadHLModel (model_t *mod, void *buffer) int len; char st[40]; - CRC_Init(&crc); + QCRC_Init(&crc); for (len = com_filesize, p = buffer; len; len--, p++) - CRC_ProcessByte(&crc, *p); + QCRC_ProcessByte(&crc, *p); sprintf(st, "%d", (int) crc); Info_SetValueForKey (cls.userinfo, diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index e83482af..cf427da7 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -574,6 +574,9 @@ couldntload: case (('O'<<24)+('M'<<16)+('Y'<<8)+'Z'): GLMod_LoadZymoticModel(mod, buf); break; + case (('K'<<24)+('R'<<16)+('A'<<8)+'D'): + GLMod_LoadDarkPlacesModel(mod, buf); + break; #endif default: //check for text based headers @@ -1213,9 +1216,9 @@ void GLMod_LoadLighting (lump_t *l) loadmodel->engineflags &= ~MDLF_RGBLIGHTING; //lit file light intensity is made to match the world's light intensity. - if (cls.allow_lightmapgamma) - BuildLightMapGammaTable(0.6, 2); - else +// if (cls.allow_lightmapgamma) +// BuildLightMapGammaTable(0.6, 2); +// else BuildLightMapGammaTable(1, 1); loadmodel->lightdata = NULL; diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c index 2a2c62e7..dc54dc3c 100644 --- a/engine/gl/gl_ppl.c +++ b/engine/gl/gl_ppl.c @@ -1414,6 +1414,7 @@ static void PPL_BaseTextureChain(msurface_t *first) msurface_t *s; int vi=-1; int redraw = false; + int dlb; glRect_t *theRect; if (first->texinfo->texture->shader->flags & SHADER_FLARE ) @@ -1427,7 +1428,10 @@ static void PPL_BaseTextureChain(msurface_t *first) mb.mesh = NULL; mb.fog = NULL; mb.infokey = -2; - mb.dlightbits = 0; + if (first->dlightframe == r_framecount) + mb.dlightbits = first->dlightbits; + else + mb.dlightbits = 0; GL_DisableMultitexture(); @@ -1480,7 +1484,11 @@ static void PPL_BaseTextureChain(msurface_t *first) if (s->mesh) { - redraw = mb.fog != s->fog || mb.infokey != vi|| mb.shader->flags&SHADER_DEFORMV_BULGE || R_MeshWillExceed(s->mesh); + if (s->dlightframe == r_framecount) + dlb = s->dlightbits; + else + dlb = 0; + redraw = mb.dlightbits != dlb || mb.fog != s->fog || mb.infokey != vi|| mb.shader->flags&SHADER_DEFORMV_BULGE || R_MeshWillExceed(s->mesh); if (redraw) { @@ -1492,6 +1500,7 @@ static void PPL_BaseTextureChain(msurface_t *first) mb.infokey = vi; mb.mesh = s->mesh; mb.fog = s->fog; + mb.dlightbits = dlb; R_PushMesh(s->mesh, mb.shader->features); } } @@ -4385,7 +4394,7 @@ qboolean PPL_AddLight(dlight_t *dl) qglDisable(GL_TEXTURE_2D); qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); qglEnable(GL_SCISSOR_TEST); -// if (!((int)r_shadows.value & 4)) + if (!((int)r_shadows.value & 4)) { qglDisable(GL_BLEND); qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 238088d6..20a745a8 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -377,7 +377,7 @@ void GLR_PushDlights (void) r_dlightframecount = r_framecount + 1; // because the count hasn't // advanced yet for this frame - if (!r_dynamic.value) + if (!r_dynamic.value || !cl.worldmodel) return; // if (!cl.worldmodel->nodes) diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 78f67f64..2f35a1eb 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -914,7 +914,7 @@ void GLR_DrawEntitiesOnList (void) continue; - if (cls.allow_anyparticles || currententity->visframe) //allowed or static + if (cl.lerpents && (cls.allow_anyparticles || currententity->visframe)) //allowed or static { if (gl_part_flame.value) { @@ -2051,7 +2051,7 @@ Thus the final mirror matrix for any given plane p*+k=0 is: gldepthmin = 0.5; gldepthmax = 1; qglDepthRange (gldepthmin, gldepthmax); - qglDepthFunc (GL_LEQUAL); + qglDepthFunc (gldepthfunc); R_RenderScene (); @@ -2061,7 +2061,7 @@ Thus the final mirror matrix for any given plane p*+k=0 is: gldepthmin = 0; gldepthmax = 0.5; qglDepthRange (gldepthmin, gldepthmax); - qglDepthFunc (GL_LEQUAL); + qglDepthFunc (gldepthfunc); memcpy(r_refdef.viewangles, oldangles, sizeof(vec3_t)); diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index d66d8a5a..8c890644 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -263,6 +263,7 @@ void GLSCR_UpdateScreen (void) SCR_SetUpToDrawConsole (); nohud = false; + #ifdef VM_CG if (CG_Refresh()) nohud = true; diff --git a/engine/gl/ltface.c b/engine/gl/ltface.c index e3eb3e28..104433a8 100644 --- a/engine/gl/ltface.c +++ b/engine/gl/ltface.c @@ -62,11 +62,9 @@ vec_t CastRay (vec3_t p1, vec3_t p2) { trace_t trace; vec3_t move; - hull_t *hull; - hull = &lightmodel->hulls[0]; - memset (&trace, 0, sizeof(trace)); - if (!lightmodel->funcs.Trace (lightmodel, 0, 0, p1, p2, vec3_origin, vec3_origin, &trace)) + lightmodel->funcs.Trace (lightmodel, 0, 0, p1, p2, vec3_origin, vec3_origin, &trace); + if (trace.fraction < 1) return -1; VectorSubtract(p1, p2, move); diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index 34f327d8..0e1100a9 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -507,9 +507,9 @@ qboolean HTTP_CL_Get(char *url, char *localfile, void (*NotifyFunction)(char *lo con->NotifyFunction = NotifyFunction; strcpy(con->filename, localfile); -/* slash = strchr(con->filename, '?'); + slash = strchr(con->filename, '?'); if (slash) - *slash = '\0';*/ + *slash = '_'; httpcl = con; diff --git a/engine/http/iwebiface.c b/engine/http/iwebiface.c index 123be95c..e5e7618b 100644 --- a/engine/http/iwebiface.c +++ b/engine/http/iwebiface.c @@ -444,7 +444,7 @@ IWEBFILE *IWebFOpenWrite(char *name, int append) //fopen(name, append?"ab":"wb" sprintf(name2, "%s%s", com_gamedir, name); else sprintf(name2, "%s/%s", com_gamedir, name); -// COM_CreatePath(name2); + COM_CreatePath(name2); f = fopen(name2, append?"ab":"wb"); if (f) { diff --git a/engine/qclib/comprout.c b/engine/qclib/comprout.c index c57c8496..4199eea0 100644 --- a/engine/qclib/comprout.c +++ b/engine/qclib/comprout.c @@ -57,6 +57,11 @@ pbool PreCompile(void) qccClearHunk(); strcpy(qcc_gamedir, ""); qcchunk = malloc(qcchunksize=128*1024*1024); + while(!qcchunk && qcchunksize > 8*1024*1024) + { + qcchunksize /= 2; + qcchunk = malloc(qcchunksize); + } qccalloced=0; return !!qcchunk; diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 12ffaf69..547f17f1 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -311,7 +311,6 @@ typedef struct QCC_type_s unsigned int ofs; //inside a structure. unsigned int size; char *name; - } QCC_type_t; int typecmp(QCC_type_t *a, QCC_type_t *b); diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 784198a0..8c34a945 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -3026,6 +3026,12 @@ QCC_def_t *QCC_MemberInParentClass(char *name, QCC_type_t *clas) //FIXME: virtual methods will not work properly. Need to trace down to see if a parent already defined it void QCC_PR_EmitFieldsForMembers(QCC_type_t *clas) { +//we created fields for each class when we defined the actual classes. +//we need to go through each member and match it to the offset of it's parent class, if overloaded, or create a new field if not.. + +//basictypefield is cleared before we do this +//we emit the parent's fields first (every time), thus ensuring that we don't reuse parent fields on a child class. + char membername[2048]; int p, np, a; unsigned int o; @@ -3058,6 +3064,7 @@ void QCC_PR_EmitFieldsForMembers(QCC_type_t *clas) ft = QCC_PR_NewType(basictypenames[mt->type], ev_field); ft->aux_type = QCC_PR_NewType(basictypenames[mt->type], mt->type); ft->aux_type->aux_type = type_void; + ft->size = ft->aux_type->size; ft = QCC_PR_FindType(ft); sprintf(membername, "__f_%s_%i", ft->name, ++basictypefield[mt->type]); f = QCC_PR_GetDef(ft, membername, NULL, true, 1); @@ -3143,13 +3150,13 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname) df->s_name = 0; df->first_statement = numstatements; df->parm_size[0] = 1; - df->numparms = 1; + df->numparms = 0; df->parm_start = numpr_globals; G_FUNCTION(scope->ofs) = df - functions; //locals here... - ed = QCC_PR_GetDef(type_entity, "ent", NULL, true, 1); + ed = QCC_PR_GetDef(type_entity, "ent", pr_scope, true, 1); virt = QCC_PR_GetDef(type_function, "spawn", NULL, false, 0); if (!virt) @@ -3173,7 +3180,8 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname) QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], oself, self, NULL)); } - QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_RETURN], &def_ret, NULL, NULL)); //apparently we do actually have to return something. *sigh*... + QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_RETURN], ed, NULL, NULL)); //apparently we do actually have to return something. *sigh*... + QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_DONE], NULL, NULL, NULL)); pr_scope = NULL; @@ -4835,9 +4843,11 @@ void QCC_PR_ParseStatement (void) if (QCC_PR_CheckKeyword(keyword_local, "local")) { + QCC_type_t *functionsclasstype = pr_classtype; // if (locals_end != numpr_globals) //is this breaking because of locals? // QCC_PR_ParseWarning("local vars after temp vars\n"); QCC_PR_ParseDefs (NULL); + pr_classtype = functionsclasstype; locals_end = numpr_globals; return; } diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index dda1321e..103fd98a 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -167,6 +167,8 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath) if (!*newfile) return; + currentfile += strlen(rootpath); //could this be bad? + for(stripfrom = currentfile+strlen(currentfile)-1; stripfrom>currentfile; stripfrom--) { if (*stripfrom == '/' || *stripfrom == '\\') @@ -2612,7 +2614,6 @@ char *TypeName(QCC_type_t *type) } else if (type->type == ev_entity && type->parentclass) { - op++; ret = buffer[op&1]; *ret = 0; strcat(ret, "class "); @@ -2995,10 +2996,11 @@ QCC_type_t *QCC_PR_ParseType (int newtype) sprintf(membername, "%s::"MEMBERFIELDNAME, classname, newparm->name); fieldtype = QCC_PR_NewType(newparm->name, ev_field); fieldtype->aux_type = newparm; + fieldtype->size = newparm->size; QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 1); - newparm->ofs = newt->size; + newparm->ofs = 0;//newt->size; newt->num_parms++; if (type) diff --git a/engine/qclib/qcdecomp.c b/engine/qclib/qcdecomp.c index e6f600d5..3c0fb8c7 100644 --- a/engine/qclib/qcdecomp.c +++ b/engine/qclib/qcdecomp.c @@ -42,7 +42,7 @@ QCC_type_t *QCC_PR_NewType (char *name, int basictype); jmp_buf decompilestatementfailure; -#if 1 +#if 0 pbool Decompile(progfuncs_t *progfuncs, char *fname) { return false; @@ -101,7 +101,7 @@ char *VarAtOfs(progfuncs_t *progfuncs, int ofs) } return buf; } - if (!*def->s_name || !strcmp(def->s_name, "IMMEDIATE")) + if (!def->s_name[progfuncs->stringtable] || !strcmp(progfuncs->stringtable+def->s_name, "IMMEDIATE")) { if (current_progstate->types) typen = current_progstate->types[def->type & ~DEF_SHARED].type; @@ -162,7 +162,7 @@ evaluateimmediate: return buf; } } - return def->s_name; + return def->s_name+progfuncs->stringtable; } @@ -296,10 +296,10 @@ void WriteStatementProducingOfs(progfuncs_t *progfuncs, progstate_t *progs, int def = ED_GlobalAtOfs16(progfuncs, ofs); if (def) { - if (!strcmp(def->s_name, "IMMEDIATE")) + if (!strcmp(def->s_name+progfuncs->stringtable, "IMMEDIATE")) writes(file, "%s", VarAtOfs(progfuncs, ofs)); else - writes(file, "%s", def->s_name); + writes(file, "%s", progfuncs->stringtable+def->s_name); } else writes(file, "%s", VarAtOfs(progfuncs, ofs)); @@ -446,12 +446,12 @@ void WriteAsmStatements(progfuncs_t *progfuncs, progstate_t *progs, int num, int writes(f, ", "); st = (void *)0xffff; - if (!*def->s_name) + if (!def->s_name[progfuncs->stringtable]) { char mem[64]; sprintf(mem, "_p_%i", def->ofs); - def->s_name = malloc(strlen(mem)+1); - strcpy(def->s_name, mem); + def->s_name = (char*)malloc(strlen(mem)+1)-progfuncs->stringtable; + strcpy(def->s_name+progfuncs->stringtable, mem); } if (current_progstate->types) @@ -460,19 +460,19 @@ void WriteAsmStatements(progfuncs_t *progfuncs, progstate_t *progs, int num, int switch(def->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) { case ev_string: - writes(f, "%s %s", "string", def->s_name); + writes(f, "%s %s", "string", progfuncs->stringtable+def->s_name); break; case ev_float: - writes(f, "%s %s", "float", def->s_name); + writes(f, "%s %s", "float", progfuncs->stringtable+def->s_name); break; case ev_entity: - writes(f, "%s %s", "entity", def->s_name); + writes(f, "%s %s", "entity", progfuncs->stringtable+def->s_name); break; case ev_vector: - writes(f, "%s %s", "vector", def->s_name); + writes(f, "%s %s", "vector", progfuncs->stringtable+def->s_name); break; default: - writes(f, "%s %s", "randomtype", def->s_name); + writes(f, "%s %s", "randomtype", progfuncs->stringtable+def->s_name); break; } } @@ -480,23 +480,23 @@ void WriteAsmStatements(progfuncs_t *progfuncs, progstate_t *progs, int num, int for (ofs = progs->functions[num].parm_start+progs->functions[num].numparms, i = progs->functions[num].numparms; i < progs->functions[num].locals; i++, ofs+=1) ofsflags[ofs] |= 4; - if (!*progs->functions[num].s_name) + if (!progfuncs->stringtable[progs->functions[num].s_name]) { char mem[64]; if (!functionname) { sprintf(mem, "_bi_%i", num); - progs->functions[num].s_name = malloc(strlen(mem)+1); - strcpy(progs->functions[num].s_name, mem); + progs->functions[num].s_name = (char*)malloc(strlen(mem)+1)-progfuncs->stringtable; + strcpy(progs->functions[num].s_name+progfuncs->stringtable, mem); } else { - progs->functions[num].s_name = malloc(strlen(functionname)+1); - strcpy(progs->functions[num].s_name, functionname); + progs->functions[num].s_name = (char*)malloc(strlen(functionname)+1)-progfuncs->stringtable; + strcpy(progs->functions[num].s_name+progfuncs->stringtable, functionname); } } - writes(f, ") %s", progs->functions[num].s_name); + writes(f, ") %s", progfuncs->stringtable+progs->functions[num].s_name); if (stn < 0) { @@ -561,34 +561,34 @@ void WriteAsmStatements(progfuncs_t *progfuncs, progstate_t *progs, int num, int writes(f, "\tlocal %s %s;\r\n", current_progstate->types[def->type&~(DEF_SHARED|DEF_SAVEGLOBAL)].name, def->s_name); else { - if (!*def->s_name) + if (!progfuncs->stringtable[def->s_name]) { char mem[64]; sprintf(mem, "_l_%i", def->ofs); - def->s_name = malloc(strlen(mem)+1); - strcpy(def->s_name, mem); + def->s_name = (char*)malloc(strlen(mem)+1)-progfuncs->stringtable; + strcpy(def->s_name+progfuncs->stringtable, mem); } switch(def->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) { case ev_string: - writes(f, "\tlocal %s %s;\r\n", "string", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "string", progfuncs->stringtable+def->s_name); break; case ev_float: - writes(f, "\tlocal %s %s;\r\n", "float", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "float", progfuncs->stringtable+def->s_name); break; case ev_entity: - writes(f, "\tlocal %s %s;\r\n", "entity", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "entity", progfuncs->stringtable+def->s_name); break; case ev_vector: if (v->vector[0] || v->vector[1] || v->vector[2]) - writes(f, "\tlocal vector %s = '%f %f %f';\r\n", def->s_name, v->vector[0], v->vector[1], v->vector[2]); + writes(f, "\tlocal vector %s = '%f %f %f';\r\n", progfuncs->stringtable+def->s_name, v->vector[0], v->vector[1], v->vector[2]); else - writes(f, "\tlocal %s %s;\r\n", "vector", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "vector", progfuncs->stringtable+def->s_name); ofs+=2; //skip floats; break; default: - writes(f, "\tlocal %s %s;\r\n", "randomtype", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "randomtype", progfuncs->stringtable+def->s_name); break; } } @@ -659,7 +659,7 @@ void WriteAsmStatements(progfuncs_t *progfuncs, progstate_t *progs, int num, int } else { - if (!strcmp(progs->functions[num].s_name, "SUB_Remove")) + if (!strcmp(progfuncs->stringtable+progs->functions[num].s_name, "SUB_Remove")) file = 0; file = f; @@ -677,34 +677,34 @@ void WriteAsmStatements(progfuncs_t *progfuncs, progstate_t *progs, int num, int writes(f, "\tlocal %s %s;\r\n", current_progstate->types[def->type&~(DEF_SHARED|DEF_SAVEGLOBAL)].name, def->s_name); else { - if (!*def->s_name) + if (!def->s_name[progfuncs->stringtable]) { char mem[64]; sprintf(mem, "_l_%i", def->ofs); - def->s_name = malloc(strlen(mem)+1); - strcpy(def->s_name, mem); + def->s_name = (char*)malloc(strlen(mem)+1)-progfuncs->stringtable; + strcpy(def->s_name+progfuncs->stringtable, mem); } switch(def->type&~(DEF_SHARED|DEF_SAVEGLOBAL)) { case ev_string: - writes(f, "\tlocal %s %s;\r\n", "string", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "string", progfuncs->stringtable+def->s_name); break; case ev_float: - writes(f, "\tlocal %s %s;\r\n", "float", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "float", progfuncs->stringtable+def->s_name); break; case ev_entity: - writes(f, "\tlocal %s %s;\r\n", "entity", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "entity", progfuncs->stringtable+def->s_name); break; case ev_vector: if (v->vector[0] || v->vector[1] || v->vector[2]) writes(f, "\tlocal vector %s = '%f %f %f';\r\n", def->s_name, v->vector[0], v->vector[1], v->vector[2]); else - writes(f, "\tlocal %s %s;\r\n", "vector", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "vector",progfuncs->stringtable+def->s_name); ofs+=2; //skip floats; break; default: - writes(f, "\tlocal %s %s;\r\n", "randomtype", def->s_name); + writes(f, "\tlocal %s %s;\r\n", "randomtype", progfuncs->stringtable+def->s_name); break; } } @@ -857,7 +857,7 @@ pbool Decompile(progfuncs_t *progfuncs, char *fname) for (i = 1; i < progs.progs->numglobaldefs; i++) { - if (!strcmp(pr_globaldefs16[i].s_name, "IMMEDIATE")) + if (!strcmp(progfuncs->stringtable+pr_globaldefs16[i].s_name, "IMMEDIATE")) continue; if (ofsflags[pr_globaldefs16[i].ofs] & 4) @@ -869,7 +869,7 @@ pbool Decompile(progfuncs_t *progfuncs, char *fname) type = pr_globaldefs16[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL); v = (eval_t *)&((int *)progs.globals)[pr_globaldefs16[i].ofs]; - if (!*pr_globaldefs16[i].s_name) + if (!progfuncs->stringtable[pr_globaldefs16[i].s_name]) { char mem[64]; if (ofsflags[pr_globaldefs16[i].ofs] & 3) @@ -879,66 +879,71 @@ pbool Decompile(progfuncs_t *progfuncs, char *fname) } sprintf(mem, "_g_%i", pr_globaldefs16[i].ofs); - pr_globaldefs16[i].s_name = malloc(strlen(mem)+1); - strcpy(pr_globaldefs16[i].s_name, mem); + pr_globaldefs16[i].s_name = (char*)malloc(strlen(mem)+1)-progfuncs->stringtable; + strcpy(pr_globaldefs16[i].s_name+progfuncs->stringtable, mem); } switch(type) { case ev_void: - writes(f, "void %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "void %s;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_string: if (v->string && *(pr_strings+v->_int)) - writes(f, "string %s = \"%s\";\r\n", pr_globaldefs16[i].s_name, pr_strings+v->_int); + writes(f, "string %s = \"%s\";\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name, pr_strings+v->_int); else writes(f, "string %s;\r\n", pr_globaldefs16[i].s_name); break; case ev_float: if (v->_float) - writes(f, "float %s = %f;\r\n", pr_globaldefs16[i].s_name, v->_float); + writes(f, "float %s = %f;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name, v->_float); else - writes(f, "float %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "float %s;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_vector: if (v->vector[0] || v->vector[1] || v->vector[2]) - writes(f, "vector %s = '%f %f %f';\r\n", pr_globaldefs16[i].s_name, v->vector[0], v->vector[1], v->vector[2]); + writes(f, "vector %s = '%f %f %f';\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name, v->vector[0], v->vector[1], v->vector[2]); else - writes(f, "vector %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "vector %s;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name); i+=3;//skip the floats break; case ev_entity: - writes(f, "entity %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "entity %s;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_field: //wierd fld++; + if (!v->_int) + writes(f, "var "); switch(pr_fielddefs16[fld].type) { case ev_string: - writes(f, ".string %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, ".string %s;", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_float: - writes(f, ".float %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, ".float %s;", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_vector: - writes(f, ".float %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, ".float %s;", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_entity: - writes(f, ".float %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, ".float %s;", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_function: - writes(f, ".void() %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, ".void() %s;", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; default: - writes(f, "field %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "field %s;", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; } + if (v->_int) + writes(f, "/* %i */", v->_int); + writes(f, "\r\n"); break; case ev_function: @@ -947,17 +952,17 @@ pbool Decompile(progfuncs_t *progfuncs, char *fname) break; case ev_pointer: - writes(f, "pointer %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "pointer %s;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_integer: - writes(f, "integer %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "integer %s;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_union: - writes(f, "union %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "union %s;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; case ev_struct: - writes(f, "struct %s;\r\n", pr_globaldefs16[i].s_name); + writes(f, "struct %s;\r\n", progfuncs->stringtable+pr_globaldefs16[i].s_name); break; default: break; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 5d86e129..433fc619 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -698,10 +698,11 @@ void PR_Decompile_f(void) { if (!svprogfuncs) { - Con_Printf("Progs not running, you need to start a server first\n"); - return; + Q_SetProgsParms(false); + PR_Configure(svprogfuncs, -1, MAX_PROGS); } + if (Cmd_Argc() == 1) svprogfuncs->Decompile(svprogfuncs, "qwprogs.dat"); else diff --git a/engine/server/q3g_public.h b/engine/server/q3g_public.h index 6c37595b..8ab35d55 100644 --- a/engine/server/q3g_public.h +++ b/engine/server/q3g_public.h @@ -1,4 +1,24 @@ -// Copyright (C) 1999-2000 Id Software, Inc. +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ // // g_public.h -- game module information visible to server @@ -10,12 +30,25 @@ // in entityStates (level eType), so the game must explicitly flag // special server behaviors #define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects + +// TTimo +// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551 +#define SVF_CLIENTMASK 0x00000002 + #define SVF_BOT 0x00000008 // set if the entity is a bot #define SVF_BROADCAST 0x00000020 // send to all connected clients #define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots #define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin // for link position (missiles and movers) -#define SVF_SINGLECLIENT 0x00000100 // only send to a single client +#define SVF_SINGLECLIENT 0x00000100 // only send to a single client (entityShared_t->singleClient) +#define SVF_NOSERVERINFO 0x00000200 // don't send CS_SERVERINFO updates to this client + // so that it can be updated for ping tools without + // lagging clients +#define SVF_CAPSULE 0x00000400 // use capsule for collision detection instead of bbox +#define SVF_NOTSINGLECLIENT 0x00000800 // send entity to everyone but one client + // (entityShared_t->singleClient) + + //=============================================================== @@ -27,7 +60,10 @@ typedef struct { int linkcount; int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc - int singleClient; // only send to this client when SVF_SINGLECLIENT is set + + // only send to this client when SVF_SINGLECLIENT is set + // if SVF_CLIENTMASK is set, use bitmask for clients to send to (maxclients must be <= 32, up to the mod to enforce this) + int singleClient; qboolean bmodel; // if false, assume an explicit mins / maxs bounding box // only set by trap_SetBrushModel @@ -70,122 +106,128 @@ typedef struct { typedef enum { //============== general Quake services ================== - G_PRINT, // ( const char *string ); 0 + G_PRINT, // ( const char *string ); // print message on the local console - G_ERROR, // ( const char *string ); 1 + G_ERROR, // ( const char *string ); // abort the game - G_MILLISECONDS, // ( void ); 2 + G_MILLISECONDS, // ( void ); // get current time for profiling reasons // this should NOT be used for any game related tasks, // because it is not journaled // console variable interaction - G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ); 3 - G_CVAR_UPDATE, // ( vmCvar_t *vmCvar ); 4 - G_CVAR_SET, // ( const char *var_name, const char *value ); 5 - G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name ); 6 + G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ); + G_CVAR_UPDATE, // ( vmCvar_t *vmCvar ); + G_CVAR_SET, // ( const char *var_name, const char *value ); + G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name ); - G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize ); 7 + G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize ); - G_ARGC, // ( void ); 8 + G_ARGC, // ( void ); // ClientCommand and ServerCommand parameter access - G_ARGV, // ( int n, char *buffer, int bufferLength ); 9 + G_ARGV, // ( int n, char *buffer, int bufferLength ); - G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode ); 10 - G_FS_READ, // ( void *buffer, int len, fileHandle_t f ); 11 - G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f ); 12 - G_FS_FCLOSE_FILE, // ( fileHandle_t f ); 13 + G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode ); + G_FS_READ, // ( void *buffer, int len, fileHandle_t f ); + G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f ); + G_FS_FCLOSE_FILE, // ( fileHandle_t f ); - G_SEND_CONSOLE_COMMAND, // ( const char *text ); 14 + G_SEND_CONSOLE_COMMAND, // ( const char *text ); // add commands to the console as if they were typed in // for map changing, etc //=========== server specific functionality ============= - G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, 15 + G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, // playerState_t *clients, int sizeofGameClient ); // the game needs to let the server system know where and how big the gentities // are, so it can look at them directly without going through an interface - G_DROP_CLIENT, // ( int clientNum, const char *reason ); 16 + G_DROP_CLIENT, // ( int clientNum, const char *reason ); // kick a client off the server with a message - G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... ); 17 + G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... ); // reliably sends a command string to be interpreted by the given // client. If clientNum is -1, it will be sent to all clients - G_SET_CONFIGSTRING, // ( int num, const char *string ); 18 + G_SET_CONFIGSTRING, // ( int num, const char *string ); // config strings hold all the index strings, and various other information // that is reliably communicated to all clients // All of the current configstrings are sent to clients when // they connect, and changes are sent to all connected clients. // All confgstrings are cleared at each level start. - G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize ); 19 + G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize ); - G_GET_USERINFO, // ( int num, char *buffer, int bufferSize ); 20 + G_GET_USERINFO, // ( int num, char *buffer, int bufferSize ); // userinfo strings are maintained by the server system, so they // are persistant across level loads, while all other game visible // data is completely reset - G_SET_USERINFO, // ( int num, const char *buffer ); 21 + G_SET_USERINFO, // ( int num, const char *buffer ); - G_GET_SERVERINFO, // ( char *buffer, int bufferSize ); 22 + G_GET_SERVERINFO, // ( char *buffer, int bufferSize ); // the serverinfo info string has all the cvars visible to server browsers - G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name ); 23 + G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name ); // sets mins and maxs based on the brushmodel name G_TRACE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ); - // collision detection against all linked entities 24 + // collision detection against all linked entities - G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum ); 25 + G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum ); // point contents against all linked entities - G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 ); 26 + G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 ); - G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 ); 27 + G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 ); - G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open ); 28 + G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open ); - G_AREAS_CONNECTED, // ( int area1, int area2 ); 29 + G_AREAS_CONNECTED, // ( int area1, int area2 ); - G_LINKENTITY, // ( gentity_t *ent ); 30 + G_LINKENTITY, // ( gentity_t *ent ); // an entity will never be sent to a client or used for collision // if it is not passed to linkentity. If the size, position, or // solidity changes, it must be relinked. - G_UNLINKENTITY, // ( gentity_t *ent ); 31 + G_UNLINKENTITY, // ( gentity_t *ent ); // call before removing an interactive entity - G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount ); 32 + G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount ); // EntitiesInBox will return brush models based on their bounding box, // so exact determination must still be done with EntityContact - G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ); 33 + G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ); // perform an exact check against inline brush models of non-square shape // access for bots to get and free a server client (FIXME?) - G_BOT_ALLOCATE_CLIENT, // ( void ); 34 + G_BOT_ALLOCATE_CLIENT, // ( void ); - G_BOT_FREE_CLIENT, // ( int clientNum ); 35 + G_BOT_FREE_CLIENT, // ( int clientNum ); - G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd ) 36 + G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd ) - G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize ) 37 + G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize ) // Retrieves the next string token from the entity spawn text, returning // false when all tokens have been parsed. // This should only be done at GAME_INIT time. - G_FS_GETFILELIST, // 38 - G_DEBUG_POLYGON_CREATE, // 39 - G_DEBUG_POLYGON_DELETE, // 40 - G_REAL_TIME, // 41 - G_SNAPVECTOR, // 42 + G_FS_GETFILELIST, + G_DEBUG_POLYGON_CREATE, + G_DEBUG_POLYGON_DELETE, + G_REAL_TIME, + G_SNAPVECTOR, + + G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ); + G_ENTITY_CONTACTCAPSULE, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ); + + // 1.32 + G_FS_SEEK, G_MEMSET = 100, G_MEMCPY, @@ -194,11 +236,11 @@ typedef enum { G_COS, G_ATAN2, G_SQRT, + G_MATRIXMULTIPLY, + G_ANGLEVECTORS, + G_PERPENDICULARVECTOR, G_FLOOR, G_CEIL, - G_TESTPRINTINT, - G_TESTPRINTFLOAT, - G_ACOS, BOTLIB_SETUP = 200, // ( void ); BOTLIB_SHUTDOWN, // ( void ); @@ -398,3 +440,4 @@ typedef enum { BOTAI_START_FRAME // ( int time ); } gameExport_t; + diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index f1c3f9f5..307f553d 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -436,7 +436,7 @@ unsigned SV_CheckModel(char *mdl) buf = (qbyte *)COM_LoadStackFile (mdl, stackbuf, sizeof(stackbuf)); if (!buf) return 0; - crc = CRC_Block(buf, com_filesize); + crc = QCRC_Block(buf, com_filesize); // for (len = com_filesize; len; len--, buf++) // CRC_ProcessByte(&crc, *buf); @@ -570,6 +570,12 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us D_FlushCaches(); cl.worldmodel = NULL; #endif + +#ifdef Q3SERVER + if (newgametype == GT_QUAKE3) + SVQ3_ShutdownGame(); //botlib kinda mandates this. :( +#endif + Mod_ClearAll (); Hunk_FreeToLowMark (host_hunklevel); @@ -1009,7 +1015,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us if (file) { char crc[12]; - sprintf(crc, "%i", CRC_Block(file, com_filesize)); + sprintf(crc, "%i", QCRC_Block(file, com_filesize)); Info_SetValueForStarKey(svs.info, "*entfile", crc, MAX_SERVERINFO_STRING); switch(svs.gametype) { diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index e4aa0d61..9372e4b0 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -150,7 +150,7 @@ cvar_t allow_luma = {"allow_luma", "1", NULL, CVAR_SERVERINFO}; cvar_t allow_bump = {"allow_bump", "1", NULL, CVAR_SERVERINFO}; cvar_t allow_skybox = {"allow_skybox", "", NULL, CVAR_SERVERINFO}; cvar_t sv_allow_splitscreen = {"allow_splitscreen", "",NULL,CVAR_SERVERINFO}; -cvar_t fbskins = {"fbskins", "0", NULL, CVAR_SERVERINFO}; //to get rid of lame fuhquake fbskins +cvar_t fbskins = {"fbskins", "1", NULL, CVAR_SERVERINFO}; //to get rid of lame fuhquake fbskins cvar_t mirrors = {"mirrors", "" , NULL, CVAR_SERVERINFO}; cvar_t sv_motd[] ={ {"sv_motd1", ""}, @@ -3520,20 +3520,22 @@ void SV_ExtractFromUserinfo (client_t *cl) } #ifdef NQPROT { - int top = atoi(Info_ValueForKey(cl->userinfo, "topcolor")); - int bottom = atoi(Info_ValueForKey(cl->userinfo, "bottomcolor")); - top &= 15; - if (top > 13) - top = 13; - bottom &= 15; - if (bottom > 13) - bottom = 13; - cl->playercolor = top*16 + bottom; - if (svs.gametype == GT_PROGS) - cl->edict->v->clientcolors = cl->playercolor; - MSG_WriteByte (&sv.nqreliable_datagram, svc_updatecolors); - MSG_WriteByte (&sv.nqreliable_datagram, cl-svs.clients); - MSG_WriteByte (&sv.nqreliable_datagram, cl->playercolor); + int top = atoi(Info_ValueForKey(cl->userinfo, "topcolor")); + int bottom = atoi(Info_ValueForKey(cl->userinfo, "bottomcolor")); + top &= 15; + if (top > 13) + top = 13; + bottom &= 15; + if (bottom > 13) + bottom = 13; + cl->playercolor = top*16 + bottom; + if (svs.gametype == GT_PROGS) + { + cl->edict->v->clientcolors = cl->playercolor; + MSG_WriteByte (&sv.nqreliable_datagram, svc_updatecolors); + MSG_WriteByte (&sv.nqreliable_datagram, cl-svs.clients); + MSG_WriteByte (&sv.nqreliable_datagram, cl->playercolor); + } } #endif } diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index c0f04e2d..f3e6dd42 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -1,7 +1,171 @@ #include "quakedef.h" +//An implementation of a Q3 server... +//requires qvm implementation and existing q3 client stuff (or at least the overlapping stuff in q3common.c). + #ifdef Q3SERVER + +//#define USEBOTLIB + +#ifdef USEBOTLIB + + + +#ifdef _WIN32 +#define QDECL __cdecl +#else +#define QDECL +#endif +#define fileHandle_t char* +#define fsMode_t int +#define pc_token_t void +#include "botlib.h" + +#define Z_TAG_BOTLIB 221726 + + +#pragma comment (lib, "H:/quake/quake3/quake3-1.32b/code/botlib/botlib_vc6/Debug/botlib_vc6.lib") + +botlib_export_t *botlib; + + + + +int COM_Compress( char *data_p ) { + char *in, *out; + int c; + qboolean newline = false, whitespace = false; + + in = out = data_p; + if (in) { + while ((c = *in) != 0) { + // skip double slash comments + if ( c == '/' && in[1] == '/' ) { + while (*in && *in != '\n') { + in++; + } + // skip /* */ comments + } else if ( c == '/' && in[1] == '*' ) { + while ( *in && ( *in != '*' || in[1] != '/' ) ) + in++; + if ( *in ) + in += 2; + // record when we hit a newline + } else if ( c == '\n' || c == '\r' ) { + newline = true; + in++; + // record when we hit whitespace + } else if ( c == ' ' || c == '\t') { + whitespace = true; + in++; + // an actual token + } else { + // if we have a pending newline, emit it (and it counts as whitespace) + if (newline) { + *out++ = '\n'; + newline = false; + whitespace = false; + } if (whitespace) { + *out++ = ' '; + whitespace = false; + } + + // copy quoted strings unmolested + if (c == '"') { + *out++ = c; + in++; + while (1) { + c = *in; + if (c && c != '"') { + *out++ = c; + in++; + } else { + break; + } + } + if (c == '"') { + *out++ = c; + in++; + } + } else { + *out = c; + out++; + in++; + } + } + } + } + *out = 0; + return out - data_p; +} + +void Com_Memset (void* dest, const int val, const size_t count) +{ + memset(dest, val, count); +} +void Com_Memcpy (void* dest, const void* src, const size_t count) +{ + memcpy(dest, src, count); +} +int Q_stricmp(char *a, char *b) +{ + return stricmp(a, b); +} +#if MSC_VER < 700 +int _ftol2 (float f) +{ + return (int)f; +} +#endif +void QDECL Com_Error( int level, const char *error, ... ) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + Sys_Error("%s", text); +} +void QDECL Com_Printf( const char *error, ... ) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + Con_Printf("%s", text); +} + +void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) +{ + int len; + va_list argptr; + char bigbuffer[32000]; // big, but small enough to fit in PPC stack + + va_start (argptr,fmt); + len = vsprintf (bigbuffer,fmt,argptr); + va_end (argptr); + if ( len >= sizeof( bigbuffer ) ) { + Com_Error( 0, "Com_sprintf: overflowed bigbuffer" ); + } + if (len >= size) { + Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); +#ifdef _DEBUG + __asm { + int 3; + } +#endif + } + Q_strncpyz (dest, bigbuffer, size ); +} +#endif + + + #include "clq3defs.h" #include "q3g_public.h" @@ -34,6 +198,7 @@ q3entityState_t *q3_baselines; static qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2); void SVQ3_CreateBaseline(void); +void SVQ3_ClientThink(client_t *cl); char *mapentspointer; @@ -324,6 +489,18 @@ int SVQ3_EntitiesInBox(vec3_t mins, vec3_t maxs, int *list, int maxcount) return SVQ3_EntitiesInBoxNode(sv_areanodes, mins, maxs, list, maxcount); } +model_t *SVQ3_ModelForEntity(q3sharedEntity_t *es) +{ + if (es->r.bmodel) + { + return Mod_ForName(va("*%i", es->s.modelindex), false); + } + else + { + return CM_TempBoxModel(es->r.mins, es->r.maxs); + } +} + #define ENTITYNUM_WORLD (MAX_GENTITIES-2) void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) { @@ -367,7 +544,9 @@ void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs, vec3_ } } - if ( entnum != ENTITYNUM_WORLD ) + if (entnum == -1) + ourowner = -1; + else if ( entnum != ENTITYNUM_WORLD ) { ourowner = GENTITY_FOR_NUM(entnum)->r.ownerNum; if (ourowner == ENTITYNUM_WORLD) @@ -401,12 +580,12 @@ void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs, vec3_ mod = Mod_ForName(va("*%i", es->s.modelindex), false); if (mod->needload) continue; - tr = CM_TransformedBoxTrace(mod, start, end, mins, maxs, 0xffffffff, es->r.currentOrigin, vec3_origin); + tr = CM_TransformedBoxTrace(mod, start, end, mins, maxs, contentmask, es->r.currentOrigin, vec3_origin); } else { mod = CM_TempBoxModel(es->r.mins, es->r.maxs); - tr = CM_TransformedBoxTrace(mod, start, end, mins, maxs, 0xffffffff, es->r.currentOrigin, es->r.currentAngles); + tr = CM_TransformedBoxTrace(mod, start, end, mins, maxs, contentmask, es->r.currentOrigin, es->r.currentAngles); // mod->funcs.Trace(mod, 0, 0, start, end, mins, maxs, &tr); } if (tr.fraction < result->fraction) @@ -426,6 +605,69 @@ void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs, vec3_ } } +int SVQ3_PointContents(vec3_t pos, int entnum) +{ + int contactlist[128]; + trace_t tr; + int i; + q3sharedEntity_t *es; + model_t *mod; + int ourowner; + + int cont; + + +// sv.worldmodel->funcs.Trace(sv.worldmodel, 0, 0, pos, pos, vec3_origin, vec3_origin, &tr); +// tr = CM_BoxTrace(sv.worldmodel, pos, pos, vec3_origin, vec3_origin, 0); + cont = CM_PointContents(sv.worldmodel, pos); + + if (entnum == -1) + ourowner = -1; + else if ( entnum != ENTITYNUM_WORLD ) + { + ourowner = GENTITY_FOR_NUM(entnum)->r.ownerNum; + if (ourowner == ENTITYNUM_WORLD) + ourowner = -1; + } + else + ourowner = -1; + + for (i = SVQ3_EntitiesInBox(pos, pos, contactlist, sizeof(contactlist)/sizeof(contactlist[0]))-1; i >= 0; i--) + { + if (contactlist[i] == entnum) + continue; //don't collide with self. + + es = GENTITY_FOR_NUM(contactlist[i]); + + if (entnum != ENTITYNUM_WORLD) + { +// if (contactlist[i] == entnum) +// continue; // don't clip against the pass entity +// if (es->r.ownerNum == entnum) +// continue; // don't clip against own missiles +// if (es->r.ownerNum == ourowner) +// continue; // don't clip against other missiles from our owner + } + + if (es->r.bmodel) + { + mod = Mod_ForName(va("*%i", es->s.modelindex), false); + if (mod->needload) + continue; + tr = CM_TransformedBoxTrace(mod, pos, pos, vec3_origin, vec3_origin, 0xffffffff, es->r.currentOrigin, vec3_origin); + } + else + { + mod = CM_TempBoxModel(es->r.mins, es->r.maxs); + tr = CM_TransformedBoxTrace(mod, pos, pos, vec3_origin, vec3_origin, 0xffffffff, es->r.currentOrigin, es->r.currentAngles); +// mod->funcs.Trace(mod, 0, 0, start, end, mins, maxs, &tr); + } + + cont |= tr.contents; + } + return cont; +} + int SVQ3_Contact(vec3_t mins, vec3_t maxs, q3sharedEntity_t *ent) { model_t *mod; @@ -523,6 +765,47 @@ void SVQ3_SetConfigString(int num, char *string) SVQ3_SendServerCommand( NULL, va("cs %i \"%s\"\n", num, string)); } +int FloatAsInt(float f) +{ + return *(int*)&f; +} + +int SVQ3_BotGetConsoleMessage( int client, char *buf, int size ) +{ + //retrieves server->client commands that were sent to a bot + client_t *cl; + int index; + + if ((unsigned)client >= MAX_CLIENTS) + return false; + + cl = &svs.clients[client]; +// cl->lastPacketTime = svs.time; + + if (cl->last_server_command_num == cl->num_server_commands) + return false; + + cl->last_server_command_num++; + index = cl->last_server_command_num & TEXTCMD_MASK; + + if ( !cl->server_commands[index][0] ) + return false; + + Q_strncpyz( buf, cl->server_commands[index], size ); + return true; +} +int SVQ3_BotGetSnapshotEntity(int client, int entnum) +{ + //fixme: does the bot actually use this?... + return -1; +} + +void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open) +{ + q3serverEntity_t *se = SENTITY_FOR_GENTITY(ge); + CMQ3_SetAreaPortalState(se->areanum, se->areanum2, open); +} + #define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) SV_Error("Call to game trap %i passes invalid pointer\n", fn); //out of bounds. long Q3G_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) { @@ -611,6 +894,15 @@ long Q3G_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) } break; + case G_BOT_FREE_CLIENT: + case G_DROP_CLIENT: + if ((unsigned)VM_LONG(arg[0]) < MAX_CLIENTS) + SV_DropClient(&svs.clients[VM_LONG(arg[0])]); + break; + + case G_BOT_ALLOCATE_CLIENT: + return SVQ3_AddBot(); + case G_ARGC: //8 return Cmd_Argc(); case G_ARGV: //9 @@ -618,6 +910,10 @@ long Q3G_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) Q_strncpyz(VM_POINTER(arg[1]), Cmd_Argv(VM_LONG(arg[0])), VM_LONG(arg[2])); break; + case G_SEND_CONSOLE_COMMAND: + Cbuf_AddText(VM_POINTER(arg[1]), RESTRICT_SERVER); + return 0; + case G_FS_FOPEN_FILE: //fopen if ((int)arg[1] + 4 >= mask || VM_POINTER(arg[1]) < offset) @@ -637,28 +933,10 @@ long Q3G_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) VMUI_fclose(VM_LONG(arg[0]), 0); break; -/* case G_FS_GETFILELIST: //fs listing + case G_FS_GETFILELIST: //fs listing if ((int)arg[2] + arg[3] >= mask || VM_POINTER(arg[2]) < offset) break; //out of bounds. - { - vmsearch_t vms; - vms.initialbuffer = vms.buffer = VM_POINTER(arg[2]); - vms.skip = strlen(VM_POINTER(arg[0]))+1; - vms.bufferleft = arg[3]; - vms.found=0; - if (*(char *)VM_POINTER(arg[0]) == '$') - { - extern char com_basedir[]; - vms.skip=0; - Sys_EnumerateFiles(com_basedir, "*", VMEnumMods, &vms); - } - else if (*(char *)VM_POINTER(arg[1]) == '.' || *(char *)VM_POINTER(arg[1]) == '/') - COM_EnumerateFiles(va("%s/*%s", VM_POINTER(arg[0]), VM_POINTER(arg[1])), VMEnum, &vms); - else - COM_EnumerateFiles(va("%s/*.%s", VM_POINTER(arg[0]), VM_POINTER(arg[1])), VMEnum, &vms); - VM_LONG(ret) = vms.found; - } - break;*/ + return VMQ3_GetFileList(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); case G_LOCATE_GAME_DATA: // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, 15 // playerState_t *clients, int sizeofGameClient ); @@ -706,12 +984,24 @@ long Q3G_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) *(char*)VM_POINTER(arg[1]) = '\0'; break; + case G_GET_SERVERINFO: + { + char *dest = VM_POINTER(arg[0]); + int length = VM_LONG(arg[1]); + Q_strncpyz(dest, svs.info, length); + } + return ; case G_GET_USERINFO://int num, char *buffer, int bufferSize 20 if (VM_OOB(arg[1], arg[2])) return 0; Q_strncpyz(VM_POINTER(arg[1]), svs.clients[VM_LONG(arg[0])].userinfo, VM_LONG(arg[2])); break; + case G_SET_USERINFO://int num, char *buffer 20 + Q_strncpyz(svs.clients[VM_LONG(arg[0])].userinfo, VM_POINTER(arg[1]), sizeof(svs.clients[0].userinfo)); + SV_ExtractFromUserinfo(&svs.clients[VM_LONG(arg[0])]); + break; + case G_LINKENTITY: // ( gentity_t *ent ); 30 Q3G_LinkEntity(VM_POINTER(arg[0])); break; @@ -732,10 +1022,12 @@ long Q3G_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) // so exact determination must still be done with EntityContact VALIDATEPOINTER(arg[2], sizeof(int*)*VM_LONG(arg[3])); return SVQ3_EntitiesInBox(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); + + case G_ADJUST_AREA_PORTAL_STATE: + SVQ3_Adjust_Area_Portal_State(VM_POINTER(arg[0]), arg[1]); break; case G_POINT_CONTENTS: - return CM_PointContents(sv.worldmodel, VM_POINTER(arg[0])); - break; + return SVQ3_PointContents(VM_POINTER(arg[0]), -1); case G_SET_BRUSH_MODEL: //ent, name VALIDATEPOINTER(arg[0], sizeof(q3sharedEntity_t)); SVQ3_SetBrushModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); @@ -779,9 +1071,9 @@ Con_Printf("builtin %i is not implemented\n", fn); case G_COS: VM_FLOAT(ret)=(float)cos(VM_FLOAT(arg[0])); break; - case G_ACOS: - VM_FLOAT(ret)=(float)acos(VM_FLOAT(arg[0])); - break; +// case G_ACOS: +// VM_FLOAT(ret)=(float)acos(VM_FLOAT(arg[0])); +// break; case G_ATAN2: VM_FLOAT(ret)=(float)atan2(VM_FLOAT(arg[0]), VM_FLOAT(arg[1])); break; @@ -795,6 +1087,431 @@ Con_Printf("builtin %i is not implemented\n", fn); VM_FLOAT(ret)=(float)ceil(VM_FLOAT(arg[0])); break; +#ifdef USEBOTLIB + case BOTLIB_SETUP: + return botlib->BotLibSetup(); + case BOTLIB_SHUTDOWN: + return botlib->BotLibShutdown(); + case BOTLIB_LIBVAR_SET: + return botlib->BotLibVarSet(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_LIBVAR_GET: + VALIDATEPOINTER(arg[1], arg[2]); + return botlib->BotLibVarGet(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2])); + case BOTLIB_PC_ADD_GLOBAL_DEFINE: + return botlib->PC_AddGlobalDefine(VM_POINTER(arg[0])); + case BOTLIB_START_FRAME: + return botlib->BotLibStartFrame(VM_FLOAT(arg[0])); + case BOTLIB_LOAD_MAP: + return botlib->BotLibLoadMap(VM_POINTER(arg[0])); + + case BOTLIB_UPDATENTITY: + return botlib->BotLibUpdateEntity(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_TEST: + return botlib->Test(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_POINTER(arg[3])); + case BOTLIB_GET_SNAPSHOT_ENTITY: + return SVQ3_BotGetSnapshotEntity(VM_LONG(arg[0]), VM_LONG(arg[1])); + case BOTLIB_GET_CONSOLE_MESSAGE: + VALIDATEPOINTER(arg[1], arg[2]); + return SVQ3_BotGetConsoleMessage(arg[0], VM_POINTER(arg[1]), VM_LONG(arg[2])); + case BOTLIB_USER_COMMAND: + { + q3usercmd_t *uc = VM_POINTER(arg[1]); + int i = VM_LONG(arg[0]); + if ((unsigned)i >= MAX_CLIENTS) + return 1; + svs.clients[i].lastcmd.angles[0] = uc->angles[0]; + svs.clients[i].lastcmd.angles[1] = uc->angles[1]; + svs.clients[i].lastcmd.angles[2] = uc->angles[2]; + svs.clients[i].lastcmd.upmove = uc->upmove; + svs.clients[i].lastcmd.sidemove = uc->rightmove; + svs.clients[i].lastcmd.forwardmove = uc->forwardmove; + svs.clients[i].lastcmd.servertime = uc->serverTime; + svs.clients[i].lastcmd.weapon = uc->weapon; + svs.clients[i].lastcmd.buttons = uc->buttons; + SVQ3_ClientThink(&svs.clients[i]); + } + return 0; + + + case BOTLIB_AAS_ENABLE_ROUTING_AREA: + return botlib->aas.AAS_EnableRoutingArea(VM_LONG(arg[0]), VM_LONG(arg[1])); + case BOTLIB_AAS_BBOX_AREAS: + //FIXME: validatepointer arg2 + return botlib->aas.AAS_BBoxAreas(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); + case BOTLIB_AAS_AREA_INFO: + return botlib->aas.AAS_AreaInfo(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AAS_ENTITY_INFO: + botlib->aas.AAS_EntityInfo(VM_LONG(arg[0]), VM_POINTER(arg[1])); + return 0; + + case BOTLIB_AAS_INITIALIZED: + return botlib->aas.AAS_Initialized(); + case BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX: + botlib->aas.AAS_PresenceTypeBoundingBox(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2])); + return 0; + case BOTLIB_AAS_TIME: + return FloatAsInt(botlib->aas.AAS_Time()); + + case BOTLIB_AAS_POINT_AREA_NUM: + return botlib->aas.AAS_PointAreaNum(VM_POINTER(arg[0])); + case BOTLIB_AAS_TRACE_AREAS: + return botlib->aas.AAS_TraceAreas(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_POINTER(arg[3]), VM_LONG(arg[4])); + + case BOTLIB_AAS_POINT_CONTENTS: + return botlib->aas.AAS_PointContents(VM_POINTER(arg[0])); + case BOTLIB_AAS_NEXT_BSP_ENTITY: + return botlib->aas.AAS_NextBSPEntity(VM_LONG(arg[0])); + case BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY: + VALIDATEPOINTER(arg[2], arg[3]); + return botlib->aas.AAS_ValueForBSPEpairKey(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); + case BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY: + VALIDATEPOINTER(arg[2], sizeof(vec3_t)); + return botlib->aas.AAS_VectorForBSPEpairKey(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2])); + case BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY: + VALIDATEPOINTER(arg[2], sizeof(float)); + return botlib->aas.AAS_FloatForBSPEpairKey(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2])); + case BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY: + VALIDATEPOINTER(arg[2], sizeof(int)); + return botlib->aas.AAS_IntForBSPEpairKey(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2])); + + case BOTLIB_AAS_AREA_REACHABILITY: + return botlib->aas.AAS_AreaReachability(VM_LONG(arg[0])); + + case BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA: + return botlib->aas.AAS_AreaTravelTimeToGoalArea(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3])); + + case BOTLIB_AAS_SWIMMING: + return botlib->aas.AAS_Swimming(VM_POINTER(arg[0])); + case BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT: + return botlib->aas.AAS_PredictClientMovement(VM_POINTER(arg[0]), + VM_LONG(arg[1]), VM_POINTER(arg[2]), + VM_LONG(arg[3]), VM_LONG(arg[4]), + VM_POINTER(arg[5]), VM_POINTER(arg[6]), + VM_LONG(arg[7]), + VM_LONG(arg[8]), VM_FLOAT(arg[9]), + VM_LONG(arg[10]), VM_LONG(arg[11]), VM_LONG(arg[12])); + + case BOTLIB_EA_SAY: + botlib->ea.EA_Say(VM_LONG(arg[0]), VM_POINTER(arg[1])); + return 0; + case BOTLIB_EA_SAY_TEAM: + botlib->ea.EA_SayTeam(VM_LONG(arg[0]), VM_POINTER(arg[1])); + return 0; + case BOTLIB_EA_COMMAND: + botlib->ea.EA_Command(VM_LONG(arg[0]), VM_POINTER(arg[1])); + return 0; + + case BOTLIB_EA_ACTION: + botlib->ea.EA_Action(VM_LONG(arg[0]), VM_LONG(arg[1])); + return 0; + case BOTLIB_EA_GESTURE: + botlib->ea.EA_Gesture(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_TALK: + botlib->ea.EA_Talk(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_ATTACK: + botlib->ea.EA_Attack(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_USE: + botlib->ea.EA_Use(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_RESPAWN: + botlib->ea.EA_Respawn(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_CROUCH: + botlib->ea.EA_Crouch(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_MOVE_UP: + botlib->ea.EA_MoveUp(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_MOVE_DOWN: + botlib->ea.EA_MoveDown(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_MOVE_FORWARD: + botlib->ea.EA_MoveForward(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_MOVE_BACK: + botlib->ea.EA_MoveBack(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_MOVE_LEFT: + botlib->ea.EA_MoveLeft(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_MOVE_RIGHT: + botlib->ea.EA_MoveRight(VM_LONG(arg[0])); + return 0; + + case BOTLIB_EA_SELECT_WEAPON: + botlib->ea.EA_SelectWeapon(VM_LONG(arg[0]), VM_LONG(arg[1])); + return 0; + case BOTLIB_EA_JUMP: + botlib->ea.EA_Jump(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_DELAYED_JUMP: + botlib->ea.EA_DelayedJump(VM_LONG(arg[0])); + return 0; + case BOTLIB_EA_MOVE: + botlib->ea.EA_Move(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_FLOAT(arg[2])); + return 0; + case BOTLIB_EA_VIEW: + botlib->ea.EA_View(VM_LONG(arg[0]), VM_POINTER(arg[1])); + return 0; + + case BOTLIB_EA_END_REGULAR: + botlib->ea.EA_EndRegular(VM_LONG(arg[0]), VM_FLOAT(arg[1])); + return 0; + case BOTLIB_EA_GET_INPUT: + botlib->ea.EA_GetInput(VM_LONG(arg[0]), VM_FLOAT(arg[1]), VM_POINTER(arg[2])); + return 0; + case BOTLIB_EA_RESET_INPUT: + botlib->ea.EA_ResetInput(VM_LONG(arg[0])); + return 0; + + + case BOTLIB_AI_LOAD_CHARACTER: + return botlib->ai.BotLoadCharacter(VM_POINTER(arg[0]), VM_FLOAT(arg[1])); + case BOTLIB_AI_FREE_CHARACTER: + botlib->ai.BotFreeCharacter(arg[0]); + return 0; + case BOTLIB_AI_CHARACTERISTIC_FLOAT: + return FloatAsInt(botlib->ai.Characteristic_Float(arg[0], arg[1])); + case BOTLIB_AI_CHARACTERISTIC_BFLOAT: + return FloatAsInt(botlib->ai.Characteristic_BFloat(arg[0], arg[1], VM_FLOAT(arg[2]), VM_FLOAT(arg[3]))); + case BOTLIB_AI_CHARACTERISTIC_INTEGER: + return botlib->ai.Characteristic_Integer(arg[0], arg[1]); + case BOTLIB_AI_CHARACTERISTIC_BINTEGER: + return botlib->ai.Characteristic_BInteger(arg[0], arg[1], arg[2], arg[3]); + case BOTLIB_AI_CHARACTERISTIC_STRING: + VALIDATEPOINTER(arg[2], arg[3]); + botlib->ai.Characteristic_String(arg[0], arg[1], VM_POINTER(arg[2]), arg[3]); + return 0; + + case BOTLIB_AI_ALLOC_CHAT_STATE: + return botlib->ai.BotAllocChatState(); + case BOTLIB_AI_FREE_CHAT_STATE: + botlib->ai.BotFreeChatState(arg[0]); + return 0; + + case BOTLIB_AI_QUEUE_CONSOLE_MESSAGE: + botlib->ai.BotQueueConsoleMessage(arg[0], arg[1], VM_POINTER(arg[2])); + return 0; + case BOTLIB_AI_REMOVE_CONSOLE_MESSAGE: + botlib->ai.BotRemoveConsoleMessage(arg[0], arg[1]); + return 0; + case BOTLIB_AI_NEXT_CONSOLE_MESSAGE: + return botlib->ai.BotNextConsoleMessage(arg[0], VM_POINTER(arg[1])); + case BOTLIB_AI_NUM_CONSOLE_MESSAGE: + return botlib->ai.BotNumConsoleMessages(arg[0]); + case BOTLIB_AI_INITIAL_CHAT: + botlib->ai.BotInitialChat(arg[0], VM_POINTER(arg[1]), arg[2], VM_POINTER(arg[3]), VM_POINTER(arg[4]), VM_POINTER(arg[5]), VM_POINTER(arg[6]), VM_POINTER(arg[7]), VM_POINTER(arg[8]), VM_POINTER(arg[9]), VM_POINTER(arg[10])); + return 0; + case BOTLIB_AI_REPLY_CHAT: + return botlib->ai.BotReplyChat(arg[0], VM_POINTER(arg[1]), arg[2], arg[3], VM_POINTER(arg[4]), VM_POINTER(arg[5]), VM_POINTER(arg[6]), VM_POINTER(arg[7]), VM_POINTER(arg[8]), VM_POINTER(arg[9]), VM_POINTER(arg[10]), VM_POINTER(arg[11])); + case BOTLIB_AI_CHAT_LENGTH: + return botlib->ai.BotChatLength(arg[0]); + case BOTLIB_AI_ENTER_CHAT: + botlib->ai.BotEnterChat(arg[0], arg[1], arg[2]); + return 0; + case BOTLIB_AI_STRING_CONTAINS: + return botlib->ai.StringContains(VM_POINTER(arg[0]), VM_POINTER(arg[1]), arg[2]); + case BOTLIB_AI_FIND_MATCH: + return botlib->ai.BotFindMatch(VM_POINTER(arg[0]), VM_POINTER(arg[1]), arg[2]); + case BOTLIB_AI_MATCH_VARIABLE: + botlib->ai.BotMatchVariable(VM_POINTER(arg[0]), arg[1], VM_POINTER(arg[2]), arg[3]); + return 0; + case BOTLIB_AI_UNIFY_WHITE_SPACES: + botlib->ai.UnifyWhiteSpaces(VM_POINTER(arg[0])); + return 0; + case BOTLIB_AI_REPLACE_SYNONYMS: + botlib->ai.BotReplaceSynonyms(VM_POINTER(arg[0]), arg[1]); + return 0; + case BOTLIB_AI_LOAD_CHAT_FILE: + return botlib->ai.BotLoadChatFile(arg[0], VM_POINTER(arg[1]), VM_POINTER(arg[2])); + case BOTLIB_AI_SET_CHAT_GENDER: + botlib->ai.BotSetChatGender(arg[0], arg[1]); + return 0; + case BOTLIB_AI_SET_CHAT_NAME: + botlib->ai.BotSetChatName(arg[0], VM_POINTER(arg[1]), arg[2]); + return 0; + + + + case BOTLIB_AI_RESET_GOAL_STATE: + botlib->ai.BotResetGoalState(VM_LONG(arg[0])); + return 0; + case BOTLIB_AI_RESET_AVOID_GOALS: + botlib->ai.BotResetAvoidGoals(VM_LONG(arg[0])); + return 0; + case BOTLIB_AI_PUSH_GOAL: + botlib->ai.BotPushGoal(VM_LONG(arg[0]), VM_POINTER(arg[1])); + return 0; + case BOTLIB_AI_POP_GOAL: + botlib->ai.BotPopGoal(VM_LONG(arg[0])); + return 0; + + case BOTLIB_AI_EMPTY_GOAL_STACK: + botlib->ai.BotEmptyGoalStack(VM_LONG(arg[0])); + return 0; + case BOTLIB_AI_DUMP_AVOID_GOALS: + botlib->ai.BotDumpAvoidGoals(VM_LONG(arg[0])); + return 0; + case BOTLIB_AI_DUMP_GOAL_STACK: + botlib->ai.BotDumpGoalStack(VM_LONG(arg[0])); + return 0; + + case BOTLIB_AI_GOAL_NAME: + VALIDATEPOINTER(arg[1], arg[2]); + botlib->ai.BotGoalName(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2])); + return 0; + + case BOTLIB_AI_GET_TOP_GOAL: + //FIXME: validatepointer ? + return botlib->ai.BotGetTopGoal(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AI_GET_SECOND_GOAL: + //FIXME: validatepointer ? + return botlib->ai.BotGetSecondGoal(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AI_CHOOSE_LTG_ITEM: + //FIXME: validatepointer ? + return botlib->ai.BotChooseLTGItem(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); + case BOTLIB_AI_CHOOSE_NBG_ITEM: + //FIXME: validatepointer ? + return botlib->ai.BotChooseNBGItem(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3]), VM_POINTER(arg[4]), VM_FLOAT(arg[5])); + case BOTLIB_AI_TOUCHING_GOAL: + return botlib->ai.BotTouchingGoal(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE: + return botlib->ai.BotItemGoalInVisButNotVisible(arg[0], VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_POINTER(arg[3])); + + case BOTLIB_AI_GET_LEVEL_ITEM_GOAL: + return botlib->ai.BotGetLevelItemGoal(arg[0], VM_POINTER(arg[1]), VM_POINTER(arg[2])); + case BOTLIB_AI_AVOID_GOAL_TIME: + return botlib->ai.BotAvoidGoalTime(arg[0], arg[1]); + case BOTLIB_AI_INIT_LEVEL_ITEMS: + botlib->ai.BotInitLevelItems(); + return 0; + + case BOTLIB_AI_UPDATE_ENTITY_ITEMS: + botlib->ai.BotUpdateEntityItems(); + return 0; + + case BOTLIB_AI_LOAD_ITEM_WEIGHTS: + return botlib->ai.BotLoadItemWeights(arg[0], VM_POINTER(arg[1])); + + case BOTLIB_AI_FREE_ITEM_WEIGHTS: + botlib->ai.BotFreeItemWeights(arg[0]); + return 0; + + case BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC: + botlib->ai.BotSaveGoalFuzzyLogic(arg[0], VM_POINTER(arg[1])); + return 0; + case BOTLIB_AI_ALLOC_GOAL_STATE: + return botlib->ai.BotAllocGoalState(VM_LONG(arg[0])); + case BOTLIB_AI_FREE_GOAL_STATE: + botlib->ai.BotFreeGoalState(VM_LONG(arg[0])); + return 0; + + case BOTLIB_AI_RESET_MOVE_STATE: + botlib->ai.BotResetMoveState(VM_LONG(arg[0])); + return 0; + case BOTLIB_AI_MOVE_TO_GOAL: + botlib->ai.BotMoveToGoal(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); + return 0; + case BOTLIB_AI_MOVE_IN_DIRECTION: + return botlib->ai.BotMoveInDirection(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_FLOAT(arg[2]), VM_LONG(arg[3])); + + case BOTLIB_AI_RESET_AVOID_REACH: + botlib->ai.BotUpdateEntityItems(); + return 0; + + case BOTLIB_AI_RESET_LAST_AVOID_REACH: + botlib->ai.BotResetLastAvoidReach(arg[0]); + return 0; + case BOTLIB_AI_REACHABILITY_AREA: + return botlib->ai.BotReachabilityArea(VM_POINTER(arg[0]), arg[1]); + + case BOTLIB_AI_MOVEMENT_VIEW_TARGET: + return botlib->ai.BotMovementViewTarget(arg[0], VM_POINTER(arg[1]), arg[2], VM_FLOAT(arg[3]), VM_POINTER(arg[4])); + + case BOTLIB_AI_ALLOC_MOVE_STATE: + return botlib->ai.BotAllocMoveState(); + case BOTLIB_AI_FREE_MOVE_STATE: + botlib->ai.BotFreeMoveState(VM_LONG(arg[0])); + return 0; + case BOTLIB_AI_INIT_MOVE_STATE: + //FIXME: validatepointer? + botlib->ai.BotInitMoveState(VM_LONG(arg[0]), VM_POINTER(arg[1])); + return 0; + + case BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON: + return botlib->ai.BotChooseBestFightWeapon(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AI_GET_WEAPON_INFO: + botlib->ai.BotGetWeaponInfo(VM_LONG(arg[0]), VM_LONG(arg[1]), VM_POINTER(arg[2])); + return 0; + case BOTLIB_AI_LOAD_WEAPON_WEIGHTS: + return botlib->ai.BotLoadWeaponWeights(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AI_ALLOC_WEAPON_STATE: + return botlib->ai.BotAllocWeaponState(); + case BOTLIB_AI_FREE_WEAPON_STATE: + botlib->ai.BotFreeWeaponState(VM_LONG(arg[0])); + return 0; + case BOTLIB_AI_RESET_WEAPON_STATE: + botlib->ai.BotResetWeaponState(VM_LONG(arg[0])); + return 0; + + case BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION: + return botlib->ai.GeneticParentsAndChildSelection(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_POINTER(arg[3]), VM_POINTER(arg[4])); + case BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC: + botlib->ai.BotInterbreedGoalFuzzyLogic(VM_LONG(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2])); + return 0; + case BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC: + botlib->ai.BotMutateGoalFuzzyLogic(VM_LONG(arg[0]), VM_FLOAT(arg[1])); + return 0; + case BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL: + return botlib->ai.BotGetNextCampSpotGoal(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AI_GET_MAP_LOCATION_GOAL: + return botlib->ai.BotGetMapLocationGoal(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AI_NUM_INITIAL_CHATS: + return botlib->ai.BotNumInitialChats(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_AI_GET_CHAT_MESSAGE: + VALIDATEPOINTER(arg[1], arg[2]); + botlib->ai.BotGetChatMessage(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2])); + return 0; + case BOTLIB_AI_REMOVE_FROM_AVOID_GOALS: + botlib->ai.BotRemoveFromAvoidGoals(VM_LONG(arg[0]), VM_LONG(arg[1])); + return 0; + case BOTLIB_AI_PREDICT_VISIBLE_POSITION: + return botlib->ai.BotPredictVisiblePosition(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3]), VM_POINTER(arg[4])); + + case BOTLIB_AI_SET_AVOID_GOAL_TIME: + botlib->ai.BotSetAvoidGoalTime(VM_LONG(arg[0]), VM_LONG(arg[1]), VM_FLOAT(arg[2])); + return 0; + + case BOTLIB_AI_ADD_AVOID_SPOT: + botlib->ai.BotAddAvoidSpot(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_FLOAT(arg[2]), VM_LONG(arg[3])); + return 0; + + case BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL: + return botlib->aas.AAS_AlternativeRouteGoals(VM_POINTER(arg[0]), arg[1], VM_POINTER(arg[2]), arg[3], arg[4], + VM_POINTER(arg[5]), arg[6], arg[7]); + case BOTLIB_AAS_PREDICT_ROUTE: + return botlib->aas.AAS_PredictRoute(VM_POINTER(arg[0]), arg[1], VM_POINTER(arg[2]), arg[3], arg[4], arg[5], arg[6], + arg[7], arg[8], arg[9], arg[10]); + case BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX: + return botlib->aas.AAS_PointReachabilityAreaIndex(VM_POINTER(arg[0])); + + case BOTLIB_PC_LOAD_SOURCE: + return botlib->PC_LoadSourceHandle(VM_POINTER(arg[0])); + case BOTLIB_PC_FREE_SOURCE: + return botlib->PC_FreeSourceHandle(VM_LONG(arg[0])); + case BOTLIB_PC_READ_TOKEN: + //fixme: validatepointer + return botlib->PC_ReadTokenHandle(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case BOTLIB_PC_SOURCE_FILE_AND_LINE: + //fixme: validatepointer + return botlib->PC_SourceFileAndLine(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2])); + +#endif + +// notimplemented: default: Con_Printf("builtin %i is not implemented\n", fn); } @@ -804,7 +1521,7 @@ Con_Printf("builtin %i is not implemented\n", fn); int EXPORT_FN Q3G_SystemCalls(int arg, ...) { - long args[9]; + long args[13]; va_list argptr; va_start(argptr, arg); @@ -817,6 +1534,10 @@ int EXPORT_FN Q3G_SystemCalls(int arg, ...) args[6]=va_arg(argptr, int); args[7]=va_arg(argptr, int); args[8]=va_arg(argptr, int); + args[9]=va_arg(argptr, int); + args[10]=va_arg(argptr, int); + args[11]=va_arg(argptr, int); + args[12]=va_arg(argptr, int); va_end(argptr); return Q3G_SystemCallsEx(NULL, ~0, arg, args); @@ -827,6 +1548,13 @@ void SVQ3_ShutdownGame(void) int i; if (!q3gamevm) return; +#ifdef USEBOTLIB + if (botlib) + { //it crashes otherwise, probably due to our huck clearage + botlib->BotLibShutdown(); + Z_FreeTags(Z_TAG_BOTLIB); + } +#endif for (i = 0; i < MAX_CONFIGSTRINGS; i++) { @@ -844,6 +1572,202 @@ void SVQ3_ShutdownGame(void) VM_Destroy(q3gamevm); q3gamevm = NULL; + + Cvar_Set(Cvar_Get("sv_running", "0", 0, "Q3 compatability"), "0"); +} + +#ifdef USEBOTLIB +void BL_Print(int l, char *fmt, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, fmt); + vsprintf (text, fmt, argptr); + va_end (argptr); + + Con_Printf("%s", text); +} + +int botlibmemoryavailable; +int BL_AvailableMemory(void) +{ + return botlibmemoryavailable; +} +void *BL_Malloc(int size) +{ + botlibmemoryavailable-=size; + return Z_TagMalloc(size, Z_TAG_BOTLIB); +} +void BL_Free(void *mem) +{ + botlibmemoryavailable+=Z_MemSize(mem); + Z_Free(mem); +} +void *BL_HunkMalloc(int size) +{ + return BL_Malloc(size);//Hunk_AllocName(size, "botlib"); +} + +int BL_FOpenFile(const char *name, fileHandle_t *handle, fsMode_t mode) +{ + return VMUI_fopen(name, handle, mode, Z_TAG_BOTLIB); +} +int BL_FRead( void *buffer, int len, fileHandle_t f ) +{ + return VMUI_FRead(buffer, len, f, Z_TAG_BOTLIB); +} +//int BL_FWrite( const void *buffer, int len, fileHandle_t f ) +//{ +// return VMUI_FWrite(buffer, len, f, Z_TAG_BOTLIB); +//} +int BL_FCloseFile( fileHandle_t f ) +{ + VMUI_fclose(f, Z_TAG_BOTLIB); + return 0; +} +//int BL_Seek( fileHandle_t f ) +//{ +// VMUI_fseek(f, Z_TAG_BOTLIB) +//} +char *BL_BSPEntityData(void) +{ + return sv.worldmodel->entities; +} +void BL_Trace(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) +{ + q3trace_t tr; + SVQ3_Trace(&tr, start, mins, maxs, end, passent, contentmask); + + trace->allsolid = tr.allsolid; + trace->startsolid = tr.startsolid; + trace->fraction = tr.fraction; + VectorCopy(tr.endpos, trace->endpos); + trace->plane = tr.plane; + trace->exp_dist = 0; + trace->sidenum = 0; + //trace->surface.name + //trace->surface.flags + trace->surface.value = tr.surfaceFlags; + trace->contents = 0;//tr.contents; + trace->ent = tr.entityNum; +} +int BL_PointContents(vec3_t point) +{ + return SVQ3_PointContents(point, -1); +} + +int BL_inPVS(vec3_t p1, vec3_t p2) +{ + return true;// FIXME: :( +} + +void BL_EntityTrace(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) +{ + trace->allsolid = 0;//tr.allsolid; + trace->startsolid = 0;//tr.startsolid; + trace->fraction = 1;//tr.fraction; + VectorCopy(end, trace->endpos); +// trace->plane = tr.plane; + trace->exp_dist = 0; + trace->sidenum = 0; + //trace->surface.name + //trace->surface.flags +// trace->surface.value = tr.surfaceFlags; + trace->contents = 0;//tr.contents; +// trace->ent = tr.entityNum; +} + +void BL_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) +{ + model_t *mod; + vec3_t mins, maxs; + float max; + int i; + + mod = Mod_ForName(va("*%i", modelnum), false); + VectorCopy(mod->mins, mins); + VectorCopy(mod->maxs, maxs); + + //if the model is rotated + if ((angles[0] || angles[1] || angles[2])) + { + // expand for rotation + max = RadiusFromBounds(mins, maxs); + for (i = 0; i < 3; i++) + { + mins[i] = -max; + maxs[i] = max; + } + } + if (outmins) + VectorCopy(mins, outmins); + if (outmaxs) + VectorCopy(maxs, outmaxs); + if (origin) + VectorClear(origin); +} +void BL_BotClientCommand(int clientnum, char *command) +{ + Cmd_TokenizeString(command, false, false); + VM_Call(q3gamevm, GAME_CLIENT_COMMAND, clientnum); +} + +#endif + +void SV_InitBotLib() +{ + cvar_t *bot_enable = Cvar_Get("bot_enable", "1", 0, "Q3 compatability"); + +#ifdef USEBOTLIB + botlib_import_t import; + + Cvar_Set(Cvar_Get("sv_mapChecksum", "0", 0, "Q3 compatability"), va("%i", sv.worldmodel->checksum)); + + memset(&import, 0, sizeof(import)); + import.Print = BL_Print; + import.Trace = BL_Trace; + import.EntityTrace = BL_EntityTrace; + import.PointContents = BL_PointContents; + import.inPVS = BL_inPVS; + import.BSPEntityData = BL_BSPEntityData; + import.BSPModelMinsMaxsOrigin = BL_BSPModelMinsMaxsOrigin; + import.BotClientCommand = BL_BotClientCommand; + import.GetMemory = BL_Malloc; + import.FreeMemory = BL_Free; + import.AvailableMemory = BL_AvailableMemory; + import.HunkAlloc = BL_HunkMalloc; + import.FS_FOpenFile = BL_FOpenFile; + import.FS_Read = BL_FRead; +// import.FS_Write = BL_FWrite; + import.FS_FCloseFile = BL_FCloseFile; +// import.FS_Seek = BL_Seek; +// import.DebugLineCreate +// import.DebugLineDelete +// import.DebugLineShow +// +// import.DebugPolygonCreate +// import.DebugPolygonDelete + +// Z_FreeTags(Z_TAG_BOTLIB); + botlibmemoryavailable = 1024*1024*16; + botlib = GetBotLibAPI(BOTLIB_API_VERSION, &import); + if (!botlib) + { + bot_enable->flags |= CVAR_LATCH; + Cvar_ForceSet(bot_enable, "0"); + } + else + { + cvar_t *mapname = Cvar_Get("mapname", "", CVAR_SERVERINFO, "Q3 compatability"); + Cvar_Set(mapname, sv.name); + } +#else + +//make sure it's switched off. + Cvar_ForceSet(bot_enable, "0"); + bot_enable->flags |= CVAR_NOSET; +#endif } qboolean SVQ3_InitGame(void) @@ -861,6 +1785,8 @@ qboolean SVQ3_InitGame(void) if (!q3gamevm) return false; + SV_InitBotLib(); + SV_ClearWorld(); q3_sentities = Z_Malloc(sizeof(q3serverEntity_t)*MAX_GENTITIES); @@ -872,6 +1798,8 @@ qboolean SVQ3_InitGame(void) Info_SetValueForKey(buffer, "sv_maxclients", "32", sizeof(buffer)); SVQ3_SetConfigString(0, buffer); + Cvar_Set(Cvar_Get("sv_running", "0", 0, "Q3 compatability"), "1"); + svq3_configstrings[1] = Z_Malloc(32); Info_SetValueForKey(svq3_configstrings[1], "sv_serverid", va("%i", svs.spawncount), MAX_SERVERINFO_STRING); @@ -886,12 +1814,20 @@ qboolean SVQ3_InitGame(void) q3_next_snapshot_entities = 0; q3_snapshot_entities = BZ_Malloc(sizeof( q3entityState_t ) * q3_num_snapshot_entities); +#ifdef USEBOTLIB + if (botlib) + VM_Call(q3gamevm, BOTAI_START_FRAME, (int)(sv.time*1000)); +#endif + return true; } void SVQ3_RunFrame(void) { VM_Call(q3gamevm, GAME_RUN_FRAME, (int)(sv.time*1000)); +#ifdef USEBOTLIB + VM_Call(q3gamevm, BOTAI_START_FRAME, (int)(sv.time*1000)); +#endif } void SVQ3_ClientCommand(client_t *cl) @@ -909,6 +1845,22 @@ void SVQ3_ClientThink(client_t *cl) VM_Call(q3gamevm, GAME_CLIENT_THINK, cl-svs.clients); } +qboolean SVQ3_Command(void) +{ + if (!q3gamevm) + return false; + + return VM_Call(q3gamevm, GAME_CONSOLE_COMMAND); +} + +qboolean SVQ3_ConsoleCommand(void) +{ + if (!q3gamevm) + return false; + Cmd_ShiftArgs(1, false); + VM_Call(q3gamevm, GAME_CONSOLE_COMMAND); + return true; +} void SVQ3_Netchan_Transmit( client_t *client, int length, qbyte *data ); @@ -1469,6 +2421,16 @@ client_t *SVQ3_FindEmptyPlayerSlot(void) } return NULL; } +client_t *SVQ3_FindExistingPlayerByIP(netadr_t na, int qport) +{ + int i; + for (i = 0; i < MAX_CLIENTS; i++) + { + if (svs.clients[i].state && NET_CompareAdr(svs.clients[i].netchan.remote_address, na)) + return &svs.clients[i]; + } + return NULL; +} qboolean Netchan_ProcessQ3 (netchan_t *chan); static qboolean SVQ3_Netchan_Process(client_t *client) @@ -1849,12 +2811,22 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and client_t *cl; char *userinfo = NULL; int ret; - int challenge = 0; + int challenge; + int qport; + if (net_message.cursize < 13) return; Huff_DecryptPacket(&net_message, 12); - cl = SVQ3_FindEmptyPlayerSlot(); + + Cmd_TokenizeString(net_message.data+4, false, false); + userinfo = Cmd_Argv(1); + qport = atoi(Info_ValueForKey(userinfo, "qport")); + challenge = atoi(Info_ValueForKey(userinfo, "challenge")); + + cl = SVQ3_FindExistingPlayerByIP(net_from, qport); //use a duplicate first. + if (!cl) + cl = SVQ3_FindEmptyPlayerSlot(); if (!cl) { @@ -1866,8 +2838,6 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and if (cl->q3frames) BZ_Free(cl->q3frames); memset(cl, 0, sizeof(*cl)); - Cmd_TokenizeString(net_message.data+4, false, false); - userinfo = Cmd_Argv(1); challenge = atoi(Info_ValueForKey(userinfo, "challenge")); if (net_from.type != NA_LOOPBACK && !SV_ChallengePasses(challenge)) @@ -1903,7 +2873,7 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and cl->name = cl->namebuf; cl->team = cl->teambuf; SV_ExtractFromUserinfo(cl); - Netchan_Setup(NS_SERVER, &cl->netchan, net_from, atoi(Info_ValueForKey(userinfo, "qport"))); + Netchan_Setup(NS_SERVER, &cl->netchan, net_from, qport); cl->netchan.outgoing_sequence = 1; cl->challenge = challenge; @@ -1918,6 +2888,26 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and cl->q3frames = BZ_Malloc(Q3UPDATE_BACKUP*sizeof(*cl->q3frames)); } +int SVQ3_AddBot(void) +{ + client_t *cl; + + cl = SVQ3_FindEmptyPlayerSlot(); + if (!cl) + return -1; //failure, no slots + + cl->protocol = SCP_BAD; + cl->state = cs_connected; + cl->name = cl->namebuf; + cl->team = cl->teambuf; + + cl->challenge = 0; + cl->userid = (cl - svs.clients)+1; + cl->state = cs_spawned; + + return cl - svs.clients; +} + void SVQ3_DropClient(client_t *cl) { if (q3gamevm) diff --git a/engine/sw/sw_draw.c b/engine/sw/sw_draw.c index d67d1b1d..61d963d6 100644 --- a/engine/sw/sw_draw.c +++ b/engine/sw/sw_draw.c @@ -410,7 +410,7 @@ void SWDraw_Init (void) } } else - concrc = CRC_Block(draw_chars, 128*128); // get CRC here because it hasn't been replaced + concrc = QCRC_Block(draw_chars, 128*128); // get CRC here because it hasn't been replaced if (!draw_chars) { //now go for hexen2 diff --git a/engine/sw/sw_model.c b/engine/sw/sw_model.c index 4e258bba..fefa7914 100644 --- a/engine/sw/sw_model.c +++ b/engine/sw/sw_model.c @@ -2268,9 +2268,9 @@ void SWMod_LoadAliasModel (model_t *mod, void *buffer) int len; char st[40]; - CRC_Init(&crc); + QCRC_Init(&crc); for (len = com_filesize, p = buffer; len; len--, p++) - CRC_ProcessByte(&crc, *p); + QCRC_ProcessByte(&crc, *p); sprintf(st, "%d", (int) crc); Info_SetValueForKey (cls.userinfo, @@ -2547,9 +2547,9 @@ void SWMod_LoadAlias2Model (model_t *mod, void *buffer) int len; char st[40]; - CRC_Init(&crc); + QCRC_Init(&crc); for (len = com_filesize, p = buffer; len; len--, p++) - CRC_ProcessByte(&crc, *p); + QCRC_ProcessByte(&crc, *p); sprintf(st, "%d", (int) crc); Info_SetValueForKey (cls.userinfo, @@ -2940,9 +2940,9 @@ void SWMod_LoadAlias3Model (model_t *mod, void *buffer) int len; char st[40]; - CRC_Init(&crc); + QCRC_Init(&crc); for (len = com_filesize, p = buffer; len; len--, p++) - CRC_ProcessByte(&crc, *p); + QCRC_ProcessByte(&crc, *p); sprintf(st, "%d", (int) crc); Info_SetValueForKey (cls.userinfo,