diff --git a/fteqtv/bsp.c b/fteqtv/bsp.c index 5eb42bf0e..c55cc8f06 100644 --- a/fteqtv/bsp.c +++ b/fteqtv/bsp.c @@ -36,8 +36,15 @@ struct bsp_s { unsigned char decpvs[(MAX_MAP_LEAFS+7)/8]; //decompressed pvs int pvsbytecount; + + + + int numintermissionspots; + intermission_t intermissionspot[8]; }; +static const intermission_t intermissionspot; + typedef struct { @@ -113,10 +120,152 @@ void DecompressVis(unsigned char *in, unsigned char *out, int bytecount) } } +void BSP_LoadEntities(bsp_t *bsp, char *entitydata) +{ + char *v; + char key[2048]; + char value[2048]; + + enum {et_random, et_startspot, et_primarystart, et_intermission} etype; + + float org[3]; + float angles[3]; + + qboolean foundstartspot = false; + float startspotorg[3]; + float startspotangles[3]; + + //char *COM_ParseToken (char *data, char *out, int outsize, const char *punctuation) + while (entitydata) + { + entitydata = COM_ParseToken(entitydata, key, sizeof(key), NULL); + if (!entitydata) + break; + + if (!strcmp(key, "{")) + { + org[0] = 0; + org[1] = 0; + org[2] = 0; + + angles[0] = 0; + angles[1] = 0; + angles[2] = 0; + etype = et_random; + + for(;;) + { + + if(!entitydata) + { + printf("unexpected eof in bsp entities section\n"); + return; + } + + entitydata = COM_ParseToken(entitydata, key, sizeof(key), NULL); + if (!strcmp(key, "}")) + break; + + entitydata = COM_ParseToken(entitydata, value, sizeof(value), NULL); + + if (!strcmp(key, "origin")) + { + v = value; + v = COM_ParseToken(v, key, sizeof(key), NULL); + org[0] = atof(key); + v = COM_ParseToken(v, key, sizeof(key), NULL); + org[1] = atof(key); + v = COM_ParseToken(v, key, sizeof(key), NULL); + org[2] = atof(key); + } + + if (!strcmp(key, "angles") || !strcmp(key, "angle") || !strcmp(key, "mangle")) + { + v = value; + v = COM_ParseToken(v, key, sizeof(key), NULL); + angles[0] = atof(key); + v = COM_ParseToken(v, key, sizeof(key), NULL); + if (v) + { + angles[1] = atof(key); + v = COM_ParseToken(v, key, sizeof(key), NULL); + angles[2] = atof(key); + } + else + { + angles[1] = angles[0]; + angles[0] = 0; + angles[2] = 0; + } + } + + + if (!strcmp(key, "classname")) + { + if (!strcmp(value, "info_player_start")) + etype = et_primarystart; + if (!strcmp(value, "info_deathmatch_start")) + etype = et_startspot; + if (!strcmp(value, "info_intermission")) + etype = et_intermission; + } + } + + switch (etype) + { + case et_primarystart: //a single player start + memcpy(startspotorg, org, sizeof(startspotorg)); + memcpy(startspotangles, angles, sizeof(startspotangles)); + foundstartspot = true; + break; + case et_startspot: + if (!foundstartspot) + { + memcpy(startspotorg, org, sizeof(startspotorg)); + memcpy(startspotangles, angles, sizeof(startspotangles)); + foundstartspot = true; + } + break; + case et_intermission: + if (bsp->numintermissionspots < sizeof(bsp->intermissionspot)/sizeof(bsp->intermissionspot[0])) + { + bsp->intermissionspot[bsp->numintermissionspots].pos[0] = org[0]; + bsp->intermissionspot[bsp->numintermissionspots].pos[1] = org[1]; + bsp->intermissionspot[bsp->numintermissionspots].pos[2] = org[2]; + + bsp->intermissionspot[bsp->numintermissionspots].angle[0] = angles[0]; + bsp->intermissionspot[bsp->numintermissionspots].angle[1] = angles[1]; + bsp->intermissionspot[bsp->numintermissionspots].angle[2] = angles[2]; + bsp->numintermissionspots++; + } + break; + } + } + else + { + printf("data not expected here\n"); + return; + } + } + + if (foundstartspot && !bsp->numintermissionspots) + { + bsp->intermissionspot[bsp->numintermissionspots].pos[0] = startspotorg[0]; + bsp->intermissionspot[bsp->numintermissionspots].pos[1] = startspotorg[1]; + bsp->intermissionspot[bsp->numintermissionspots].pos[2] = startspotorg[2]; + + bsp->intermissionspot[bsp->numintermissionspots].angle[0] = startspotangles[0]; + bsp->intermissionspot[bsp->numintermissionspots].angle[1] = startspotangles[1]; + bsp->intermissionspot[bsp->numintermissionspots].angle[2] = startspotangles[2]; + bsp->numintermissionspots++; + } +} + bsp_t *BSP_LoadModel(cluster_t *cluster, char *gamedir, char *bspname) { unsigned char *data; unsigned int size; + char *entdata; dheader_t *header; dplane_t *planes; @@ -159,10 +308,13 @@ bsp_t *BSP_LoadModel(cluster_t *cluster, char *gamedir, char *bspname) nodes = (dnode_t*)(data+LittleLong(header->lumps[LUMP_NODES].fileofs)); leaf = (dleaf_t*)(data+LittleLong(header->lumps[LUMP_LEAFS].fileofs)); + entdata = (char*)(data+LittleLong(header->lumps[LUMP_ENTITIES].fileofs)); + numnodes = LittleLong(header->lumps[LUMP_NODES].filelen)/sizeof(dnode_t); numleafs = LittleLong(header->lumps[LUMP_LEAFS].filelen)/sizeof(dleaf_t); bsp = malloc(sizeof(bsp_t) + sizeof(node_t)*numnodes + LittleLong(header->lumps[LUMP_VISIBILITY].filelen) + sizeof(unsigned char *)*numleafs); + bsp->numintermissionspots = 0; if (bsp) { bsp->fullchecksum = 0; @@ -204,6 +356,8 @@ bsp_t *BSP_LoadModel(cluster_t *cluster, char *gamedir, char *bspname) } } + BSP_LoadEntities(bsp, entdata); + free(data); return bsp; @@ -318,3 +472,16 @@ void BSP_SetupForPosition(bsp_t *bsp, float x, float y, float z) DecompressVis(bsp->pvsofs[leafnum], bsp->decpvs, bsp->pvsbytecount); } +const intermission_t *BSP_IntermissionSpot(bsp_t *bsp) +{ + int spotnum; + if (bsp) + { + if (bsp->numintermissionspots>0) + { + spotnum = rand()%bsp->numintermissionspots; + return &bsp->intermissionspot[spotnum]; + } + } + return &intermissionspot; +} \ No newline at end of file diff --git a/fteqtv/parse.c b/fteqtv/parse.c index fe553e2df..1c6cc1841 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -1688,7 +1688,7 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask) if (tv->bsp) BSP_Free(tv->bsp); - if (tv->cluster->nobsp || !tv->usequkeworldprotocols) + if (tv->cluster->nobsp)// || !tv->usequkeworldprotocols) tv->bsp = NULL; else tv->bsp = BSP_LoadModel(tv->cluster, tv->gamedir, tv->modellist[1].name); diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 198d91cfb..015c31bb4 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -496,6 +496,11 @@ typedef struct { char bits[6]; } nail_t; +typedef struct { + float pos[3]; + float angle[3]; +} intermission_t; + struct sv_s { char connectpassword[64]; //password given to server netadr_t serveraddress; @@ -879,7 +884,9 @@ unsigned int BSP_Checksum(bsp_t *bsp); int BSP_SphereLeafNums(bsp_t *bsp, int maxleafs, unsigned short *list, float x, float y, float z, float radius); qboolean BSP_Visible(bsp_t *bsp, int leafcount, unsigned short *list); void BSP_SetupForPosition(bsp_t *bsp, float x, float y, float z); -void QW_SetViewersServer(viewer_t *viewer, sv_t *sv); +const intermission_t *BSP_IntermissionSpot(bsp_t *bsp); + +void QW_SetViewersServer(cluster_t *cluster, viewer_t *viewer, sv_t *sv); unsigned short QCRC_Block (unsigned char *start, int count); unsigned short QCRC_Value(unsigned short crcvalue); void WriteDeltaUsercmd (netmsg_t *m, const usercmd_t *from, usercmd_t *move); diff --git a/fteqtv/qw.c b/fteqtv/qw.c index a2d871f4e..562a223b8 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -23,6 +23,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static const filename_t ConnectionlessModelList[] = {{""}, {"maps/start.bsp"}, {"progs/player.mdl"}, {""}}; static const filename_t ConnectionlessSoundList[] = {{""}, {""}}; +void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean noupwards); + void QTV_DefaultMovevars(movevars_t *vars) { vars->gravity = 800; @@ -620,8 +622,26 @@ int SendList(sv_t *qtv, int first, const filename_t *list, int svc, netmsg_t *ms return i; } -void QW_SetViewersServer(viewer_t *viewer, sv_t *sv) +void QW_StreamPrint(cluster_t *cluster, sv_t *server, viewer_t *allbut, char *message) { + viewer_t *v; + + for (v = cluster->viewers; v; v = v->next) + { + if (v->server == server) + { + if (v == allbut) + continue; + QW_PrintfToViewer(v, "%s", message); + } + } +} + +void QW_SetViewersServer(cluster_t *cluster, viewer_t *viewer, sv_t *sv) +{ + char buffer[1024]; + sv_t *oldserver; + oldserver = viewer->server; if (viewer->server) viewer->server->numviewers--; viewer->server = sv; @@ -635,6 +655,17 @@ void QW_SetViewersServer(viewer_t *viewer, sv_t *sv) viewer->origin[0] = 0; viewer->origin[1] = 0; viewer->origin[2] = 0; + + if (sv != oldserver) + { + if (sv) + { + snprintf(buffer, sizeof(buffer), "%cQTV%c%s leaves to watch %s (%i)\n", 91+128, 93+128, viewer->name, *sv->hostname?sv->hostname:sv->server, sv->streamid); + QW_StreamPrint(cluster, oldserver, viewer, buffer); + } + snprintf(buffer, sizeof(buffer), "%cQTV%c%s joins the stream\n", 91+128, 93+128, viewer->name); + QW_StreamPrint(cluster, sv, viewer, buffer); + } } //fixme: will these want to have state?.. @@ -655,16 +686,8 @@ void NewClient(cluster_t *cluster, viewer_t *viewer) viewer->timeout = cluster->curtime + 15*1000; viewer->trackplayer = -1; - - if (!viewer->server) - { - QW_SetMenu(viewer, MENU_SERVERS); - } - else - { - viewer->menunum = -1; - QW_SetMenu(viewer, MENU_NONE); - } + viewer->menunum = -1; + QW_SetMenu(viewer, MENU_NONE); QW_PrintfToViewer(viewer, "Welcome to FTEQTV build %i\n", cluster->buildnumber); @@ -682,11 +705,22 @@ void NewClient(cluster_t *cluster, viewer_t *viewer) QW_StuffcmdToViewer(viewer, "alias \"proxy:menu\" \"say proxy:menu\"\n"); QW_StuffcmdToViewer(viewer, "alias \"proxy:backspace\" \"say proxy:menu backspace\"\n"); + QW_StuffcmdToViewer(viewer, "alias \".help\" \"say .help\"\n"); + QW_StuffcmdToViewer(viewer, "alias \".disconnect\" \"say .disconnect\"\n"); + QW_StuffcmdToViewer(viewer, "alias \".menu\" \"say .menu\"\n"); + QW_StuffcmdToViewer(viewer, "alias \".admin\" \"say .admin\"\n"); + QW_StuffcmdToViewer(viewer, "alias \".reset\" \"say .reset\"\n"); + QW_StuffcmdToViewer(viewer, "alias \".clients\" \"say .clients\"\n"); +// QW_StuffcmdToViewer(viewer, "alias \".qtv\" \"say .qtv\"\n"); +// QW_StuffcmdToViewer(viewer, "alias \".join\" \"say .join\"\n"); +// QW_StuffcmdToViewer(viewer, "alias \".observe\" \"say .observe\"\n"); + QW_PrintfToViewer(viewer, "Type admin for the admin menu\n"); } void ParseUserInfo(cluster_t *cluster, viewer_t *viewer) { + char buf[1024]; float rate; char temp[64]; Info_ValueForKey(viewer->userinfo, "name", temp, sizeof(temp)); @@ -695,6 +729,27 @@ void ParseUserInfo(cluster_t *cluster, viewer_t *viewer) strcpy(temp, "unnamed"); if (!*viewer->name) Sys_Printf(cluster, "Viewer %s connected\n", temp); + + if (strcmp(viewer->name, temp)) + { + if (*viewer->name) + { + snprintf(buf, sizeof(buf), "%cQTV%c%s changed name to %cQTV%c%s\n", + 91+128, 93+128, viewer->name, + 91+128, 93+128, temp + ); + } + else + { + snprintf(buf, sizeof(buf), "%cQTV%c%s joins the stream\n", + 91+128, 93+128, temp + ); + + } + + QW_StreamPrint(cluster, viewer->server, NULL, buf); + } + Q_strncpyz(viewer->name, temp, sizeof(viewer->name)); Info_ValueForKey(viewer->userinfo, "rate", temp, sizeof(temp)); @@ -855,6 +910,8 @@ void QW_SetMenu(viewer_t *v, int menunum) { if (menunum != MENU_NONE) { + QW_StuffcmdToViewer(v, "//set prox_inmenu 1\n"); + QW_StuffcmdToViewer(v, "alias \"+proxfwd\" \"proxy:up\"\n"); QW_StuffcmdToViewer(v, "alias \"+proxback\" \"proxy:down\"\n"); QW_StuffcmdToViewer(v, "alias \"+proxleft\" \"proxy:left\"\n"); @@ -867,6 +924,8 @@ void QW_SetMenu(viewer_t *v, int menunum) } else { + QW_StuffcmdToViewer(v, "//set prox_inmenu 0\n"); + QW_StuffcmdToViewer(v, "alias \"+proxfwd\" \"+forward\"\n"); QW_StuffcmdToViewer(v, "alias \"+proxback\" \"+back\"\n"); QW_StuffcmdToViewer(v, "alias \"+proxleft\" \"+moveleft\"\n"); @@ -1419,7 +1478,6 @@ void SendNQClientData(sv_t *tv, viewer_t *v, netmsg_t *msg) void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg) { - int miss; int e; int i; usercmd_t to; @@ -2139,7 +2197,7 @@ void PMove(viewer_t *v, usercmd_t *cmd) v->velocity[2] = pmove.velocity[2]; } -void QW_SetCommentator(viewer_t *v, viewer_t *commentator) +void QW_SetCommentator(cluster_t *cluster, viewer_t *v, viewer_t *commentator) { // if (v->commentator == commentator) // return; @@ -2154,7 +2212,7 @@ void QW_SetCommentator(viewer_t *v, viewer_t *commentator) QW_PrintfToViewer(v, "Following commentator %s\n", commentator->name); if (v->server != commentator->server) - QW_SetViewersServer(v, commentator->server); + QW_SetViewersServer(cluster, v, commentator->server); } else { @@ -2195,7 +2253,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean qtv = QTV_NewServerConnection(cluster, buf, "", false, false, false); if (qtv) { - QW_SetViewersServer(v, qtv); + QW_SetViewersServer(cluster, v, qtv); QW_PrintfToViewer(v, "Connected\n", message); } else @@ -2215,6 +2273,19 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean Sys_Printf(cluster, "Player %s gets incorrect admin password\n", v->name); } } + else if (!strcmp(v->expectcommand, "insecadddemo")) + { + snprintf(buf, sizeof(buf), "file:%s", message); + qtv = QTV_NewServerConnection(cluster, buf, "", false, false, false); + if (!qtv) + QW_PrintfToViewer(v, "Failed to play demo \"%s\"\n", message); + else + { + QW_SetViewersServer(cluster, v, qtv); + QW_PrintfToViewer(v, "Opened demo file.\n", message); + } + } + else if (!strcmp(v->expectcommand, "adddemo")) { snprintf(buf, sizeof(buf), "file:%s", message); @@ -2223,7 +2294,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean QW_PrintfToViewer(v, "Failed to play demo \"%s\"\n", message); else { - QW_SetViewersServer(v, qtv); + QW_SetViewersServer(cluster, v, qtv); QW_PrintfToViewer(v, "Opened demo file.\n", message); } } @@ -2277,11 +2348,41 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean ".bind\n" ); } + + else if (!strncmp(message, ".menu", 5)) + { + message += 5; + + if (v->conmenussupported) + goto guimenu; + else + goto tuimenu; + } + + else if (!strncmp(message, ".tuimenu", 8)) + { + message += 8; + +tuimenu: + if (v->menunum) + QW_SetMenu(v, MENU_NONE); + else + QW_SetMenu(v, MENU_SERVERS); + } else if (!strncmp(message, ".guimenu", 8)) { sv_t *sv; int y; - qboolean shownheader = false; + qboolean shownheader; + + message += 8; + +guimenu: + + QW_SetMenu(v, MENU_NONE); + + shownheader = false; + QW_StuffcmdToViewer(v, "alias menucallback\n" @@ -2402,16 +2503,9 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean } else if (!strncmp(message, ".reset", 6)) { - QW_SetViewersServer(v, NULL); + QW_SetViewersServer(cluster, v, NULL); QW_SetMenu(v, MENU_SERVERS); } - else if (!strncmp(message, ".menu", 5)) - { - if (v->menunum) - QW_SetMenu(v, MENU_NONE); - else - QW_SetMenu(v, MENU_SERVERS); - } else if (!strncmp(message, ".admin", 6)) { if (!*cluster->adminpassword) @@ -2444,7 +2538,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (qtv) { QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(v, qtv); + QW_SetViewersServer(cluster, v, qtv); QW_PrintfToViewer(v, "Connected\n", message); } else @@ -2458,7 +2552,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (qtv) { QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(v, qtv); + QW_SetViewersServer(cluster, v, qtv); qtv->controller = v; QW_PrintfToViewer(v, "Connected\n", message); } @@ -2473,7 +2567,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (qtv) { QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(v, qtv); + QW_SetViewersServer(cluster, v, qtv); QW_PrintfToViewer(v, "Connected\n", message); } else @@ -2494,7 +2588,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (qtv) { QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(v, qtv); + QW_SetViewersServer(cluster, v, qtv); QW_PrintfToViewer(v, "Connected\n", message); } else @@ -2510,7 +2604,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (qtv) { QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(v, qtv); + QW_SetViewersServer(cluster, v, qtv); QW_PrintfToViewer(v, "Connected\n", message); } else @@ -2519,7 +2613,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean else if (!strncmp(message, ".disconnect", 11)) { QW_SetMenu(v, MENU_SERVERS); - QW_SetViewersServer(v, NULL); + QW_SetViewersServer(cluster, v, NULL); QW_PrintfToViewer(v, "Connected\n", message); } else if (!strncmp(message, "admin", 11)) @@ -2544,12 +2638,12 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (ov->server) { if (ov->server->controller == ov) - QW_PrintfToViewer(v, "%s: %s\n", ov->name, ov->server->server); + QW_PrintfToViewer(v, "%i: %s: %s\n", ov->userid, ov->name, ov->server->server); else - QW_PrintfToViewer(v, "%s: %s\n", ov->name, ov->server->server); + QW_PrintfToViewer(v, "%i: %s: %s\n", ov->userid, ov->name, ov->server->server); } else - QW_PrintfToViewer(v, "%s: %s\n", ov->name, "None"); + QW_PrintfToViewer(v, "%i: %s: %s\n", ov->userid, ov->name, "None"); } else remaining++; @@ -2557,21 +2651,21 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (remaining) QW_PrintfToViewer(v, "%i clients not shown\n", remaining); } - else if (!strncmp(message, ".followid ", 8)) + else if (!strncmp(message, ".followid ", 10)) { - int id = atoi(message+8); + int id = atoi(message+10); viewer_t *cv; for (cv = cluster->viewers; cv; cv = cv->next) { if (cv->userid == id) { - QW_SetCommentator(v, cv); + QW_SetCommentator(cluster, v, cv); return; } } QW_PrintfToViewer(v, "Couldn't find that player\n"); - QW_SetCommentator(v, NULL); + QW_SetCommentator(cluster, v, NULL); } else if (!strncmp(message, ".follow ", 8)) { @@ -2582,16 +2676,16 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean { if (!strcmp(cv->name, id)) { - QW_SetCommentator(v, cv); + QW_SetCommentator(cluster, v, cv); return; } } QW_PrintfToViewer(v, "Couldn't find that player\n"); - QW_SetCommentator(v, NULL); + QW_SetCommentator(cluster, v, NULL); } else if (!strncmp(message, ".follow", 7)) { - QW_SetCommentator(v, NULL); + QW_SetCommentator(cluster, v, NULL); } else if (!strncmp(message, "proxy:menu up", 13)) { @@ -2659,6 +2753,52 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean QW_PrintfToViewer(v, "All keys bound not recognised\n"); } + else if (!strncmp(message, ".bsay ", 6)) + { + viewer_t *ov; + if (cluster->notalking) + return; + + message += 6; + + for (ov = cluster->viewers; ov; ov = ov->next) + { + InitNetMsg(&msg, buf, sizeof(buf)); + + WriteByte(&msg, svc_print); + + if (ov->netchan.isnqprotocol) + WriteByte(&msg, 1); + else + { + if (ov->conmenussupported) + { + WriteByte(&msg, 3); //PRINT_CHAT + WriteString2(&msg, "[^sBQTV^s]^s^5"); + } + else + { + WriteByte(&msg, 2); //PRINT_HIGH + WriteByte(&msg, 91+128); + WriteString2(&msg, "BQTV"); + WriteByte(&msg, 93+128); + WriteByte(&msg, 0); + + WriteByte(&msg, svc_print); + WriteByte(&msg, 3); //PRINT_CHAT + + } + } + + WriteString2(&msg, v->name); + WriteString2(&msg, ": "); +// WriteString2(&msg, "\x8d "); + WriteString2(&msg, message); + WriteString(&msg, "\n"); + + SendBufferToViewer(ov, msg.data, msg.cursize, true); + } + } else if (!strncmp(message, ".", 1) && strncmp(message, "..", 2)) { QW_PrintfToViewer(v, "Proxy command not recognised\n"); @@ -2709,16 +2849,25 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (ov->conmenussupported) { WriteByte(&msg, 3); //PRINT_CHAT - WriteString2(&msg, "^s^5"); + WriteString2(&msg, "[^sQTV^s]^s^5"); } else { + WriteByte(&msg, 2); //PRINT_HIGH + WriteByte(&msg, 91+128); + WriteString2(&msg, "QTV"); + WriteByte(&msg, 93+128); + WriteByte(&msg, 0); + + WriteByte(&msg, svc_print); WriteByte(&msg, 3); //PRINT_CHAT + } } WriteString2(&msg, v->name); - WriteString2(&msg, "\x8d "); + WriteString2(&msg, ": "); +// WriteString2(&msg, "\x8d "); WriteString2(&msg, message); WriteString(&msg, "\n"); @@ -2767,6 +2916,37 @@ void QW_StuffcmdToViewer(viewer_t *v, char *format, ...) SendBufferToViewer(v, buf, strlen(buf)+1, true); } +void QW_PositionAtIntermission(sv_t *qtv, viewer_t *v) +{ + netmsg_t msg; + char buf[4]; + const intermission_t *spot; + + + if (qtv) + spot = BSP_IntermissionSpot(qtv->bsp); + else + spot = BSP_IntermissionSpot(NULL); + + + v->origin[0] = spot->pos[0]; + v->origin[1] = spot->pos[1]; + v->origin[2] = spot->pos[2]; + + + msg.data = buf; + msg.maxsize = sizeof(buf); + msg.cursize = 0; + msg.overflowed = 0; + + WriteByte (&msg, svc_setangle); + WriteByte (&msg, (spot->angle[0]/360) * 256); + WriteByte (&msg, (spot->angle[1]/360) * 256); + WriteByte (&msg, 0);//spot->angle[2]); + + SendBufferToViewer(v, msg.data, msg.cursize, true); +} + void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) { char buf[MAX_NQMSGLEN]; @@ -2861,11 +3041,21 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) SendNQSpawnInfoToViewer(cluster, v, &msg); SendBufferToViewer(v, msg.data, msg.cursize, true); + QW_PositionAtIntermission(qtv, v); + v->thinksitsconnected = true; } else if (!strncmp(buf, "begin", 5)) { + int oldmenu; v->thinksitsconnected = true; + + oldmenu = v->menunum; + QW_SetMenu(v, MENU_NONE); + QW_SetMenu(v, oldmenu); + + if (!v->server) + QTV_Say(cluster, v->server, v, ".menu", false); } else if (!strncmp(buf, "say \"", 5)) @@ -2930,12 +3120,14 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) // usercmd_t oldest, oldcmd, newcmd; char buf[1024]; netmsg_t msg; + int i; v->delta_frame = -1; while (m->readpos < m->cursize) { - switch (ReadByte(m)) + i = ReadByte(m); + switch (i) { case clc_nop: return; @@ -3075,9 +3267,12 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) char skin[64]; sprintf(skin, "%cskins\n", svc_stufftext); SendBufferToViewer(v, skin, strlen(skin)+1, true); + + QW_PositionAtIntermission(qtv, v); } else if (!strncmp(buf, "begin", 5)) { + int oldmenu; viewer_t *com; if (atoi(buf+6) != v->servercount) SendServerData(qtv, v); //this is unfortunate! @@ -3089,11 +3284,20 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) char msgb[] = {svc_setpause, 1}; SendBufferToViewer(v, msgb, sizeof(msgb), true); } - } - com = v->commentator; - v->commentator = NULL; - QW_SetCommentator(v, com); + oldmenu = v->menunum; + QW_SetMenu(v, MENU_NONE); + QW_SetMenu(v, oldmenu); + + + com = v->commentator; + v->commentator = NULL; + QW_SetCommentator(cluster, v, com); + + + if (!v->server) + QTV_Say(cluster, v->server, v, ".menu", false); + } } else if (!strncmp(buf, "download", 8)) { @@ -3132,7 +3336,7 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) else if (!strncmp(buf, "ptrack", 6)) { v->trackplayer = -1; - QW_SetCommentator(v, NULL); + QW_SetCommentator(cluster, v, NULL); } else if (!strncmp(buf, "pings", 5)) { @@ -3259,6 +3463,7 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) return; default: + Sys_Printf(cluster, "bad clc from %s\n", v->name); v->drop = true; return; } @@ -3326,7 +3531,7 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum) } else*/ { - QW_SetViewersServer(viewer, sv); + QW_SetViewersServer(cluster, viewer, sv); QW_SetMenu(viewer, MENU_NONE); viewer->thinksitsconnected = false; } @@ -3406,6 +3611,10 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer) unsigned char *s; netmsg_t m; + + if (viewer->backbuffered) + return; + InitNetMsg(&m, buffer, sizeof(buffer)); WriteByte(&m, svc_centerprint); @@ -3594,11 +3803,15 @@ static const char dropcmd[] = {svc_stufftext, 'd', 'i', 's', 'c', 'o', 'n', 'n', void QW_FreeViewer(cluster_t *cluster, viewer_t *viewer) { + char buf[1024]; viewer_t *oview; int i; //note: unlink them yourself. -// Sys_Printf(cluster, "Dropping viewer %s\n", viewer->name); + snprintf(buf, sizeof(buf), "%cQTV%c%s leaves the proxy\n", 91+128, 93+128, viewer->name); + QW_StreamPrint(cluster, viewer->server, NULL, buf); + + Sys_Printf(cluster, "Dropping viewer %s\n", viewer->name); //spam them thrice, then forget about them Netchan_Transmit(cluster, &viewer->netchan, strlen(dropcmd)+1, dropcmd); @@ -3622,7 +3835,7 @@ void QW_FreeViewer(cluster_t *cluster, viewer_t *viewer) for (oview = cluster->viewers; oview; oview = oview->next) { if (oview->commentator == viewer) - QW_SetCommentator(oview, NULL); + QW_SetCommentator(cluster, oview, NULL); } free(viewer); @@ -3803,6 +4016,7 @@ void QW_UpdateUDPStuff(cluster_t *cluster) { if (Net_CompareAddress(&v->netchan.remote_address, &from, 0, 0)) { + Sys_Printf(cluster, "Dup connect from %s\n", v->name); v->drop = true; } } diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index cc3736c7d..3bcaddf8f 100644 --- a/fteqtv/rcon.c +++ b/fteqtv/rcon.c @@ -527,6 +527,14 @@ char *Cmd_Status(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffe catbuffer(buffer, sizeofbuffer, " Talking allowed\n"); if (cluster->nobsp) catbuffer(buffer, sizeofbuffer, " No BSP loading\n"); + if (cluster->tcpsocket != INVALID_SOCKET) + { + catbuffer(buffer, sizeofbuffer, " tcp port %i\n", cluster->tcplistenportnum); + } + if (cluster->tcpsocket != INVALID_SOCKET) + { + catbuffer(buffer, sizeofbuffer, " udp port %i\n", cluster->qwlistenportnum); + } catbuffer(buffer, sizeofbuffer, "\n"); @@ -557,6 +565,9 @@ char *Cmd_Status(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffe if (*qtv->connectpassword) catbuffer(buffer, sizeofbuffer, "Using a password\n"); + if (qtv->disconnectwhennooneiswatching) + catbuffer(buffer, sizeofbuffer, "Stream is temporary\n"); + if (qtv->tcpsocket != INVALID_SOCKET) { catbuffer(buffer, sizeofbuffer, "Listening for proxies (%i)\n", qtv->tcplistenportnum); @@ -762,11 +773,11 @@ char *Cmd_MVDPort(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buff if (!newp) { - if (qtv->tcpsocket != INVALID_SOCKET) + if (cluster->tcpsocket != INVALID_SOCKET) { - closesocket(qtv->tcpsocket); - qtv->tcpsocket = INVALID_SOCKET; - qtv->tcplistenportnum = 0; + closesocket(cluster->tcpsocket); + cluster->tcpsocket = INVALID_SOCKET; + cluster->tcplistenportnum = 0; return "mvd port is now closed\n"; } @@ -778,11 +789,10 @@ char *Cmd_MVDPort(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buff if (news != INVALID_SOCKET) { - if (qtv->tcpsocket != INVALID_SOCKET) - closesocket(qtv->tcpsocket); - qtv->tcpsocket = news; - qtv->disconnectwhennooneiswatching = false; - qtv->tcplistenportnum = newp; + if (cluster->tcpsocket != INVALID_SOCKET) + closesocket(cluster->tcpsocket); + cluster->tcpsocket = news; + cluster->tcplistenportnum = newp; return "Opened tcp port\n"; } else @@ -859,8 +869,8 @@ const rconcommands_t rconcommands[] = {"disconnect", 1, 0, Cmd_Disconnect}, {"record", 1, 0, Cmd_Record}, {"stop", 1, 0, Cmd_Stop}, - {"tcpport", 1, 0, Cmd_MVDPort}, - {"mvdport", 1, 0, Cmd_MVDPort}, + {"tcpport", 0, 1, Cmd_MVDPort}, + {"mvdport", 0, 1, Cmd_MVDPort}, #ifdef VIEWER {"watch", 1, 0, Cmd_Watch}, diff --git a/fteqtv/source.c b/fteqtv/source.c index c11ee442b..6624b4530 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -864,8 +864,9 @@ void QTV_Shutdown(sv_t *qtv) { if (v->server == qtv) { - QW_SetViewersServer(v, NULL); - QW_SetMenu(v, MENU_SERVERS); + QW_SetViewersServer(qtv->cluster, v, NULL); + QW_SetMenu(v, MENU_NONE); + QTV_Say(cluster, v->server, v, ".menu", false); QW_PrintfToViewer(v, "Stream %s is closing\n", qtv->server); } }