diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index a81840c77..089c0880b 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -630,6 +630,7 @@ void CL_CheckForResend (void) char data[2048]; double t1, t2; int contype = 0; + qboolean keeptrying = true; #ifndef CLIENTONLY if (!cls.state && sv.state) @@ -828,6 +829,8 @@ void CL_CheckForResend (void) if (!NET_EnsureRoute(cls.sockets, "conn", cls.servername, false)) { Con_Printf ("Unable to establish connection to %s\n", cls.servername); + connect_time = -1; + SCR_EndLoadingPlaque(); return; } @@ -839,7 +842,7 @@ void CL_CheckForResend (void) if (contype & 1) { Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge\n", 255, 255, 255, 255); - NET_SendPacket (NS_CLIENT, strlen(data), data, &adr); + keeptrying &= NET_SendPacket (NS_CLIENT, strlen(data), data, &adr); } /*NQ*/ #ifdef NQPROT @@ -871,11 +874,18 @@ void CL_CheckForResend (void) MSG_WriteString(&sb, "getchallenge"); *(int*)sb.data = LongSwap(NETFLAG_CTL | sb.cursize); - NET_SendPacket (NS_CLIENT, sb.cursize, sb.data, &adr); + keeptrying &= NET_SendPacket (NS_CLIENT, sb.cursize, sb.data, &adr); } #endif connect_tries++; + + if (!keeptrying) + { + Con_TPrintf ("No route to host, giving up\n"); + connect_time = -1; + SCR_EndLoadingPlaque(); + } } void CL_BeginServerConnect(int port) diff --git a/engine/client/m_single.c b/engine/client/m_single.c index ac90b4f7e..d845ba76c 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -340,7 +340,7 @@ void M_Menu_SinglePlayer_f (void) { MC_AddPicture(menu, 72, 32, 232, 64, "gfx/sp_menu.lmp"); - b = MC_AddConsoleCommand (menu, 16, 32, "", "closemenu\nmaxclients 1;deathmatch 0;coop 0;map start\n"); + b = MC_AddConsoleCommand (menu, 16, 32, "", "closemenu;disconnect;maxclients 1;deathmatch 0;coop 0;map start\n"); menu->selecteditem = (menuoption_t *)b; b->common.width = p->width; b->common.height = 20; diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 1668b38f5..d67402b35 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -1498,7 +1498,7 @@ static struct { {"hash_getcb", PF_hash_getcb, 293}, {"checkcommand", PF_checkcommand, 294}, //gap - {"print", PF_print, 339}, + {"print_csqc", PF_print, 339}, {"keynumtostring_csqc", PF_cl_keynumtostring, 340}, {"stringtokeynum", PF_cl_stringtokeynum, 341}, {"getkeybind", PF_cl_getkeybind, 342}, @@ -1880,6 +1880,8 @@ qboolean MP_Init (void) PR_ExecuteProgram(menu_world.progs, mp_init_function); inmenuprogs--; + EDICT_NUM(menu_world.progs, 0)->readonly = true; + Con_DPrintf("Initialized menu.dat\n"); return true; } diff --git a/engine/client/render.h b/engine/client/render.h index 7b40a1507..8fcf34ee6 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -412,7 +412,8 @@ qbyte *R_MarkLeaves_Q3 (void); void R_SetFrustum (float projmat[16], float viewmat[16]); void R_SetRenderer(rendererinfo_t *ri); void R_AnimateLight (void); -struct texture_s *R_TextureAnimation (int frame, struct texture_s *base); +struct texture_s *R_TextureAnimation (int frame, struct texture_s *base); //mostly deprecated, only lingers for rtlights so world only. +struct texture_s *R_TextureAnimation_Q2 (struct texture_s *base); //mostly deprecated, only lingers for rtlights so world only. void RQ_Init(void); void RQ_Shutdown(void); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index cc4cdda4c..69ffd3456 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -339,8 +339,8 @@ cvar_t r_shadows = SCVARF ("r_shadows", "0", cvar_t r_showbboxes = CVARD("r_showbboxes", "0", "Debugging. Shows bounding boxes. 1=ssqc, 2=csqc. Red=solid, Green=stepping/toss/bounce, Blue=onground."); cvar_t r_lightprepass = CVARFD("r_lightprepass", "0", CVAR_SHADERSYSTEM, "Experimental. Attempt to use a different lighting mechanism."); -cvar_t r_shadow_bumpscale_basetexture = SCVAR ("r_shadow_bumpscale_basetexture", "4"); -cvar_t r_shadow_bumpscale_bumpmap = SCVAR ("r_shadow_bumpscale_bumpmap", "10"); +cvar_t r_shadow_bumpscale_basetexture = CVARD ("r_shadow_bumpscale_basetexture", "0", "bumpyness scaler for generation of fallback normalmap textures from models"); +cvar_t r_shadow_bumpscale_bumpmap = CVARD ("r_shadow_bumpscale_bumpmap", "4", "bumpyness scaler for _bump textures"); cvar_t r_glsl_offsetmapping = CVARF ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM); cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04"); @@ -1742,6 +1742,29 @@ texture_t *R_TextureAnimation (int frame, texture_t *base) return base; } +texture_t *R_TextureAnimation_Q2 (texture_t *base) +{ + int reletive; + int frame; + + if (!base->anim_total) + return base; + + //this is only ever used on world. everything other than rtlights have proper batches. + frame = cl.time*2; //q2 is lame + + reletive = frame % base->anim_total; + + while (reletive --> 0) + { + base = base->anim_next; + if (!base) + Sys_Error ("R_TextureAnimation: broken cycle"); + } + + return base; +} + diff --git a/engine/common/net.h b/engine/common/net.h index f8b6d3bf1..d5d55976d 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -92,7 +92,7 @@ void NET_CloseServer (void); void UDP_CloseSocket (int socket); void NET_Shutdown (void); int NET_GetPacket (netsrc_t netsrc, int firstsock); -void NET_SendPacket (netsrc_t socket, int length, void *data, netadr_t *to); +qboolean NET_SendPacket (netsrc_t socket, int length, void *data, netadr_t *to); int NET_LocalAddressForRemote(struct ftenet_connections_s *collection, netadr_t *remote, netadr_t *local, int idx); void NET_PrintAddresses(struct ftenet_connections_s *collection); qboolean NET_AddressSmellsFunny(netadr_t *a); diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 87d4493d3..1ba87b582 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -2716,6 +2716,8 @@ qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon) { Con_TPrintf ("Connection lost or aborted\n"); //server died/connection lost. } + else if (err == ENOTCONN) + Con_Printf ("TCPConnect_GetPacket: connection failed\n"); else Con_Printf ("TCPConnect_GetPacket: Error (%i): %s\n", err, strerror(err)); @@ -4242,6 +4244,7 @@ typedef struct qboolean havepacket; qboolean failed; + int showerror; } ftenet_websocket_connection_t; static void websocketgot(void *user_data, int32_t result) @@ -4255,6 +4258,7 @@ static void websocketgot(void *user_data, int32_t result) { Sys_Printf("%s: %i\n", __func__, result); wsc->failed = true; + wsc->showerror = result; } } static void websocketconnected(void *user_data, int32_t result) @@ -4274,6 +4278,7 @@ static void websocketconnected(void *user_data, int32_t result) Sys_Printf("%s: %i\n", __func__, result); //some sort of error connecting, make it timeout now wsc->failed = true; + wsc->showerror = result; } } static void websocketclosed(void *user_data, int32_t result) @@ -4368,6 +4373,54 @@ static qboolean FTENET_NaClWebSocket_GetPacket(ftenet_generic_connection_t *gcon } return true; } + + if (wsc->showerror != PP_OK) + { + switch(wsc->showerror) + { + case PP_ERROR_FAILED: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_FAILED\n"); + break; + case PP_ERROR_ABORTED: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_ABORTED\n"); + break; + case PP_ERROR_NOTSUPPORTED: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_NOTSUPPORTED\n"); + break; + case PP_ERROR_CONNECTION_CLOSED: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_CONNECTION_CLOSED\n"); + break; + case PP_ERROR_CONNECTION_RESET: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_CONNECTION_RESET\n"); + break; + case PP_ERROR_CONNECTION_REFUSED: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_CONNECTION_REFUSED\n"); + break; + case PP_ERROR_CONNECTION_ABORTED: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_CONNECTION_ABORTED\n"); + break; + case PP_ERROR_CONNECTION_FAILED: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_CONNECTION_FAILED\n"); + break; + case PP_ERROR_CONNECTION_TIMEDOUT: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_CONNECTION_TIMEDOUT\n"); + break; + case PP_ERROR_ADDRESS_INVALID: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_ADDRESS_INVALID\n"); + break; + case PP_ERROR_ADDRESS_UNREACHABLE: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_ADDRESS_UNREACHABLE\n"); + break; + case PP_ERROR_ADDRESS_IN_USE: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: PP_ERROR_ADDRESS_IN_USE\n"); + break; + default: + Con_TPrintf ("FTENET_NaClWebSocket_GetPacket: error %i\n", wsc->showerror); + break; + } + wsc->showerror = PP_OK; + } + return false; } static qboolean FTENET_NaClWebSocket_SendPacket(ftenet_generic_connection_t *gcon, int length, void *data, netadr_t *to) @@ -4520,9 +4573,9 @@ int NET_LocalAddressForRemote(ftenet_connections_t *collection, netadr_t *remote return collection->conn[remote->connum-1]->GetLocalAddress(collection->conn[remote->connum-1], local, idx); } -void NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t *to) +qboolean NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t *to) { - char buffer[64]; +// char buffer[64]; ftenet_connections_t *collection; int i; @@ -4530,7 +4583,7 @@ void NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t *to) { #ifdef CLIENTONLY Sys_Error("NET_GetPacket: Bad netsrc"); - return; + return false; #else collection = svs.sockets; #endif @@ -4539,26 +4592,26 @@ void NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t *to) { #ifdef SERVERONLY Sys_Error("NET_GetPacket: Bad netsrc"); - return; + return false; #else collection = cls.sockets; #endif } if (!collection) - return; + return false; if (net_fakeloss.value) { if (frandom () < net_fakeloss.value) - return; + return true; } if (to->connum) { if (collection->conn[to->connum-1]) if (collection->conn[to->connum-1]->SendPacket(collection->conn[to->connum-1], length, data, to)) - return; + return true; } for (i = 0; i < MAX_CONNECTIONS; i++) @@ -4566,10 +4619,11 @@ void NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t *to) if (!collection->conn[i]) continue; if (collection->conn[i]->SendPacket(collection->conn[i], length, data, to)) - return; + return true; } - Con_Printf("No route to %s - try reconnecting\n", NET_AdrToString(buffer, sizeof(buffer), to)); +// Con_Printf("No route to %s - try reconnecting\n", NET_AdrToString(buffer, sizeof(buffer), to)); + return false; } qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char *host, qboolean islisten) @@ -4586,6 +4640,7 @@ qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char case NA_IRC: if (!FTENET_AddToCollection(collection, routename, host, adr.type, islisten)) return false; + Con_Printf("Establishing connection to %s\n", host); break; default: //not recognised, or not needed diff --git a/engine/common/netinc.h b/engine/common/netinc.h index 770cf3d02..78576bbc8 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -124,6 +124,9 @@ #ifdef EACCES #undef EACCES #endif + #ifdef ENOTCONN + #undef ENOTCONN + #endif #define EWOULDBLOCK WSAEWOULDBLOCK #define EINPROGRESS WSAEINPROGRESS diff --git a/engine/common/world.h b/engine/common/world.h index 18e631b10..7fea6d8b2 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -122,6 +122,7 @@ typedef struct q2trace_s #define MOVE_EVERYTHING 32 //can return triggers and non-solid items if they're marked with FINDABLE_NONSOLID (works even if the items are not properly linked) #define MOVE_LAGGED 64 //trace touches current last-known-state, instead of actual ents (just affects players for now) #define MOVE_ENTCHAIN 128 //chain of impacted ents, otherwise result shows only world +#define MOVE_ONLYENT 256 //test the trace against a single entity, ignoring non-solid/owner/etc flags (but respecting contents). typedef struct areanode_s { diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 6579b2c89..2f2b8255a 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -2754,10 +2754,7 @@ static void BE_SubmitMeshesSortList(batch_t *sortlist) if (batch->buildmeshes) batch->buildmeshes(batch); else if (batch->texture) - { - batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader; batch->skin = &batch->shader->defaulttextures; - } if (batch->shader->flags & SHADER_NODLIGHT) if (shaderstate.mode == BEM_LIGHT) @@ -3037,9 +3034,6 @@ static void BE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist) if (batch->buildmeshes) batch->buildmeshes(batch); - else - batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader; - /*draw already-drawn portals as depth-only, to ensure that their contents are not harmed*/ BE_SelectMode(BEM_DEPTHONLY); diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index a370d0306..040caf749 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -3467,10 +3467,10 @@ void GLBE_Scissor(srect_t *rect) { qglScissor( floor(r_refdef.pxrect.x + rect->x*r_refdef.pxrect.width), - floor((r_refdef.pxrect.y + rect->y*r_refdef.pxrect.height) - r_refdef.pxrect.maxheight), + floor(r_refdef.pxrect.y + rect->y*r_refdef.pxrect.height),// - r_refdef.pxrect.maxheight), ceil(rect->width * r_refdef.pxrect.width), ceil(rect->height * r_refdef.pxrect.height)); -// qglEnable(GL_SCISSOR_TEST); + qglEnable(GL_SCISSOR_TEST); if (qglDepthBoundsEXT) { @@ -4115,9 +4115,6 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist) if (batch->buildmeshes) batch->buildmeshes(batch); -// else -// batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader; - /*draw already-drawn portals as depth-only, to ensure that their contents are not harmed*/ GLBE_SelectMode(BEM_DEPTHONLY); @@ -4200,6 +4197,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) if ((batch->shader->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT | SHADER_HASRIPPLEMAP)) && shaderstate.mode != BEM_WIREFRAME) { + float oldil; int oldbem; //these flags require rendering some view as an fbo if (r_refdef.recurse) @@ -4207,6 +4205,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) if (shaderstate.mode != BEM_STANDARD && shaderstate.mode != BEM_DEPTHDARK) continue; oldbem = shaderstate.mode; + oldil = shaderstate.identitylighting; if ((batch->shader->flags & SHADER_HASREFLECT) && gl_config.ext_framebuffer_objects) { @@ -4344,6 +4343,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) GL_ViewportUpdate(); } BE_SelectMode(oldbem); + shaderstate.identitylighting = oldil; } GLBE_SubmitBatch(batch); diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index d837ae829..71eba397f 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -89,7 +89,7 @@ void GL_UploadFmt(texid_t tex, char *name, enum uploadfmt fmt, void *data, void texid_t GL_LoadTextureFmt (char *name, int width, int height, enum uploadfmt fmt, void *data, unsigned int flags) { - extern cvar_t r_shadow_bumpscale_basetexture; + extern cvar_t r_shadow_bumpscale_basetexture, r_shadow_bumpscale_bumpmap; switch(fmt) { case TF_INVALID: @@ -117,8 +117,9 @@ texid_t GL_LoadTextureFmt (char *name, int width, int height, enum uploadfmt fmt return GL_LoadTexture(name, width, height, data, flags, 4); case TF_HEIGHT8PAL: - case TF_HEIGHT8: return GL_LoadTexture8Bump(name, width, height, data, flags, r_shadow_bumpscale_basetexture.value); + case TF_HEIGHT8: + return GL_LoadTexture8Bump(name, width, height, data, flags, r_shadow_bumpscale_bumpmap.value); default: Sys_Error("Unsupported image format type\n"); diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index a9b9cdea2..3956ade03 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -2601,7 +2601,10 @@ static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour) if (!sm->batches[tno].count) continue; tex = cl.worldmodel->shadowbatches[tno].tex; - shader = R_TextureAnimation(false, tex)->shader; + if (cl.worldmodel->fromgame == fg_quake2) + shader = R_TextureAnimation_Q2(tex)->shader; + else + shader = R_TextureAnimation(false, tex)->shader; if (shader->flags & SHADER_NODLIGHT) continue; //FIXME: it may be worth building a dedicated ebo @@ -3248,9 +3251,9 @@ void Sh_PreGenerateLights(void) if (r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival) { - if (rtlights_first == rtlights_max) + if (RTL_FIRST == rtlights_max) R_LoadRTLights(); - if (rtlights_first == rtlights_max) + if (RTL_FIRST == rtlights_max) R_ImportRTLights(cl.worldmodel->entities); } diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index 83e224f68..a8c9c1990 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -342,17 +342,11 @@ reeval: ptr->_int = (int)OPA->_float; break; case OP_STOREP_I: - case OP_GSTOREP_I: case OP_STOREP_F: - case OP_GSTOREP_F: case OP_STOREP_ENT: - case OP_GSTOREP_ENT: case OP_STOREP_FLD: // integers - case OP_GSTOREP_FLD: case OP_STOREP_S: - case OP_GSTOREP_S: case OP_STOREP_FNC: // pointers - case OP_GSTOREP_FNC: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; @@ -362,11 +356,10 @@ reeval: ptr->_int = OPA->_int; break; case OP_STOREP_V: - case OP_GSTOREP_V: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); ptr->_vector[0] = OPA->_vector[0]; @@ -378,7 +371,7 @@ reeval: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); *(unsigned char *)ptr = (char)OPA->_float; @@ -397,7 +390,7 @@ reeval: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); OPC->_float = (ptr->_float *= OPA->_float); @@ -406,7 +399,7 @@ reeval: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } tmpf = OPA->_float; ptr = QCPOINTER(OPB); @@ -422,7 +415,7 @@ reeval: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); OPC->_float = (ptr->_float /= OPA->_float); @@ -440,7 +433,7 @@ reeval: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); OPC->_float = (ptr->_float += OPA->_float); @@ -449,7 +442,7 @@ reeval: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); OPC->_vector[0] = (ptr->_vector[0] += OPA->_vector[0]); @@ -469,7 +462,7 @@ reeval: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); OPC->_float = (ptr->_float -= OPA->_float); @@ -478,7 +471,7 @@ reeval: if (QCPOINTERWRITEFAIL(OPB)) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); OPC->_vector[0] = (ptr->_vector[0] -= OPA->_vector[0]); @@ -664,6 +657,7 @@ reeval: PR_SwitchProgsParms(progfuncs, callerprogs); //break/skip the instruction. + PR_StackTrace(&progfuncs->funcs); printf(msg, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); #ifndef DEBUGABLE progfuncs->funcs.pr_trace++; @@ -1168,14 +1162,61 @@ reeval: break; case OP_GADDRESS: //return glob[aint+bfloat] + //this instruction is not implemented due to the weirdness of it. + //its theoretically a more powerful load... but untyped? + //or is it meant to be an LEA instruction (that could simply be switched with + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "OP_GADDRESS not implemented (found in %s)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + break; case OP_GLOAD_I: case OP_GLOAD_F: case OP_GLOAD_FLD: case OP_GLOAD_ENT: case OP_GLOAD_S: case OP_GLOAD_FNC: - pr_xstatement = st-pr_statements; - PR_RunError(&progfuncs->funcs, "Extra opcode not implemented\n"); + if (OPA->_int < 0 || OPA->_int*4 >= current_progstate->globals_size) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = ((eval_t *)&glob[OPA->_int]); + OPC->_int = ptr->_int; + break; + case OP_GLOAD_V: + if (OPA->_int < 0 || (OPA->_int+2)*4 >= current_progstate->globals_size) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = ((eval_t *)&glob[OPA->_int]); + OPC->_vector[0] = ptr->_vector[0]; + OPC->_vector[1] = ptr->_vector[1]; + OPC->_vector[2] = ptr->_vector[2]; + break; + case OP_GSTOREP_I: + case OP_GSTOREP_F: + case OP_GSTOREP_ENT: + case OP_GSTOREP_FLD: + case OP_GSTOREP_S: + case OP_GSTOREP_FNC: + if (OPB->_int < 0 || OPB->_int*4 >= current_progstate->globals_size) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = ((eval_t *)&glob[OPB->_int]); + ptr->_int = OPA->_int; + break; + case OP_GSTOREP_V: + if (OPB->_int < 0 || (OPB->_int+2)*4 >= current_progstate->globals_size) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = ((eval_t *)&glob[OPB->_int]); + ptr->_vector[0] = OPA->_vector[0]; + ptr->_vector[1] = OPA->_vector[1]; + ptr->_vector[2] = OPA->_vector[2]; break; case OP_BOUNDCHECK: diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 738092e39..07d7e9685 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -9551,11 +9551,11 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"pointparticles", PF_sv_pointparticles,0, 0, 0, 337, D("void(float effectnum, vector origin, optional vector dir, optional float count)", "Spawn a load of particles from the given effect at the given point traveling or aiming along the direction specified. The number of particles are scaled by the count argument.")},// (EXT_CSQC) {"cprint", PF_Fixme, 0, 0, 0, 338, D("void(string s, ...)", "Print into the center of the screen just as ssqc's centerprint would appear.")},//(EXT_CSQC) - {"print", PF_print, 0, 0, 0, 339, D("void(string s, ...)", "Unambiguously print on the local system's console, even in ssqc (doesn't care about the value of the developer cvar).")},//(EXT_CSQC) + {"print", PF_print, 0, 0, 0, 339, D("void(string s, ...)", "Unconditionally print on the local system's console, even in ssqc (doesn't care about the value of the developer cvar).")},//(EXT_CSQC) {"keynumtostring", PF_Fixme, 0, 0, 0, 340, D("string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (EXT_CSQC) - {"keynumtostring_csqc", PF_Fixme, 0, 0, 0, 340, D("string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (found in menuqc) + {"keynumtostring_csqc",PF_Fixme,0, 0, 0, 340, D("string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (found in menuqc) {"stringtokeynum", PF_Fixme, 0, 0, 0, 341, D("float(string keyname)", "Looks up the key name in the same way that the bind command would, returning the keycode for that key.")},// (EXT_CSQC) {"getkeybind", PF_Fixme, 0, 0, 0, 342, D("string(float keynum)", "Finds the current binding for the given key (ignores modifiers like shift/alt/ctrl).")},// (EXT_CSQC) diff --git a/engine/server/savegame.c b/engine/server/savegame.c index dac21a432..827483721 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -549,7 +549,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea #ifdef Q2SERVER if (gametype == GT_QUAKE2) { - char syspath[MAX_OSPATH]; + flocation_t loc; SV_SpawnServer (level, startspot, false, false); World_ClearWorld(&sv.world); @@ -559,10 +559,17 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea return false; } - if (!FS_NativePath(name, FS_GAME, syspath, sizeof(syspath))) + if (!FS_FLocateFile(name, FSLFRT_IFFOUND, &loc)) + { + Con_Printf("Couldn't find %s.\n", name); return false; - - ge->ReadLevel(syspath); + } + if (!*loc.rawname || loc.offset) + { + Con_Printf("%s is inside a package and cannot be used by the quake2 gamecode.\n", name); + return false; + } + ge->ReadLevel(loc.rawname); for (i=0 ; i<100 ; i++) //run for 10 secs to iron out a few bugs. ge->RunFrame (); @@ -1068,6 +1075,18 @@ void SV_Savegame (char *savename) VFS_PRINTF (f, "%s\n", sv.name); VFS_CLOSE(f); + +#ifdef Q2SERVER + //save the player's inventory and other map-persistant state that is owned by the gamecode. + if (ge) + { + char syspath[256]; + if (!FS_NativePath(va("saves/%s/game.gsv", savename), FS_GAMEONLY, syspath, sizeof(syspath))) + return; + ge->WriteGame(syspath, false); + FS_FlushFSHashReally(); + } +#endif } void SV_Savegame_f (void) @@ -1264,6 +1283,24 @@ void SV_Loadgame_f (void) VFS_CLOSE(f); +#ifdef Q2SERVER + if (gametype == GT_QUAKE2) + { + flocation_t loc; + char *name = va("saves/%s/game.gsv", savename); + if (!FS_FLocateFile(name, FSLFRT_IFFOUND, &loc)) + Con_Printf("Couldn't find %s.\n", name); + else if (!*loc.rawname || loc.offset) + Con_Printf("%s is inside a package and cannot be used by the quake2 gamecode.\n", name); + else + { + SVQ2_InitGameProgs(); + if (ge) + ge->ReadGame(loc.rawname); + } + } +#endif + svs.gametype = gametype; SV_LoadLevelCache(savename, str, "", true); sv.allocated_client_slots = slots; diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index e469d65f9..306798dbb 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -724,7 +724,7 @@ qboolean SVQ2_InitGameProgs(void) } // unload anything we have now - if (sv.world.worldmodel->fromgame == fg_quake || sv.world.worldmodel->fromgame == fg_halflife) //we don't support q1 or hl maps yet... If ever. + if (sv.world.worldmodel && (sv.world.worldmodel->fromgame == fg_quake || sv.world.worldmodel->fromgame == fg_halflife)) //we don't support q1 or hl maps yet... If ever. { SVQ2_ShutdownGameProgs(); return false; @@ -790,7 +790,7 @@ qboolean SVQ2_InitGameProgs(void) import.SetAreaPortalState = CMQ2_SetAreaPortalState; import.AreasConnected = PFQ2_AreasConnected; - if (sv.world.worldmodel->fromgame == fg_quake || sv.world.worldmodel->fromgame == fg_halflife) + if (sv.world.worldmodel && (sv.world.worldmodel->fromgame == fg_quake || sv.world.worldmodel->fromgame == fg_halflife)) { return false; /* diff --git a/engine/server/world.c b/engine/server/world.c index 5655e568e..4dab692d9 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -1709,6 +1709,13 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e else clip.hitcontentsmask = MASK_POINTSOLID; /*ignores playerclip but hits everything else*/ + if (type & MOVE_ONLYENT) + { + if (!passedict) + passedict = w->edicts; + return World_ClipMoveToEntity (w, passedict, passedict->v->origin, start, mins, maxs, end, hullnum, clip.type & MOVE_HITMODEL, clip.hitcontentsmask); + } + // clip to world clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, start, mins, maxs, end, hullnum, false, clip.hitcontentsmask); diff --git a/engine/sw/sw_backend.c b/engine/sw/sw_backend.c index c11abb909..03a254199 100644 --- a/engine/sw/sw_backend.c +++ b/engine/sw/sw_backend.c @@ -495,8 +495,6 @@ static void SWBE_SubmitMeshesSortList(batch_t *sortlist) if (batch->buildmeshes) batch->buildmeshes(batch); - else if (batch->texture) - batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader; if (batch->shader->flags & SHADER_NODRAW) continue;