razorace Posted September 12, 2006 Share Posted September 12, 2006 I'm in the process of intergrating all the bugfixes into OJP and I notice that I can't replicate the following bug. Ensiform, if there maybe additional conditions for this bug to occur? Thanks! 2. bot_minplayers removerandom bot bug where it kicks spectators watching them instead of the bot: change the following in g_bot.c: trap_SendConsoleCommand( EXEC_INSERT, va("kick \"%s\"\n", netname) ); to trap_SendConsoleCommand( EXEC_INSERT, va("clientkick \"%d\"\n", cl->ps.clientNum)); Edit: Also, Ensiform, would you mind adding additional position information for those bugs mentioned in the starting post? I'd feel more comfortable if I could see exactly where the code is supposed to go. Maybe just show the line of code that preceeds the patched code? Thanks! Link to comment Share on other sites More sharing options...
razorace Posted September 13, 2006 Share Posted September 13, 2006 Also, the bug fix for item 1 in Enisform's first post doesn't fully work. It looks like currentOrigin doesn't work for spectators so you gotta do a spectator check and then return values based on that. As such, the proper fix should be.... g_cmd.c void Cmd_Where_f( gentity_t *ent ) { trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) ); } to g_cmd.c void Cmd_Where_f( gentity_t *ent ) { if(ent->client && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {//active players use currentOrigin trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->r.currentOrigin ) ) ); } else { trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) ); } } Link to comment Share on other sites More sharing options...
razorace Posted September 13, 2006 Share Posted September 13, 2006 Alternate fix for a dead body's color didn't match the player's color in team games. The fix offered by Enisform doesn't conform to the way team colors are normally forced on the player. In addition, I think that Ensiform's method might cause problems with dead body colors in siege. g_client.c: SetupGameGhoul2Model() Change if ( g_gametype.integer >= GT_TEAM && g_gametype.integer != GT_SIEGE && !g_trueJedi.integer ) { BG_ValidateSkinForTeam( truncModelName, skin, ent->client->sess.sessionTeam, NULL ); } to if ( g_gametype.integer >= GT_TEAM && g_gametype.integer != GT_SIEGE && !g_trueJedi.integer ) { //Also adjust customRGBA for team colors. float colorOverride[3]; colorOverride[0] = colorOverride[1] = colorOverride[2] = 0.0f; BG_ValidateSkinForTeam( truncModelName, skin, ent->client->sess.sessionTeam, colorOverride); if (colorOverride[0] != 0.0f || colorOverride[1] != 0.0f || colorOverride[2] != 0.0f) { ent->client->ps.customRGBA[0] = colorOverride[0]*255.0f; ent->client->ps.customRGBA[1] = colorOverride[1]*255.0f; ent->client->ps.customRGBA[2] = colorOverride[2]*255.0f; } } ClientUserinfoChanged() After client->ps.customRGBA[3]=255; Add if ( g_gametype.integer >= GT_TEAM && g_gametype.integer != GT_SIEGE && !g_trueJedi.integer ) { char skin[MAX_QPATH]; float colorOverride[3]; colorOverride[0] = colorOverride[1] = colorOverride[2] = 0.0f; BG_ValidateSkinForTeam( model, skin, client->sess.sessionTeam, colorOverride); if (colorOverride[0] != 0.0f || colorOverride[1] != 0.0f || colorOverride[2] != 0.0f) { client->ps.customRGBA[0] = colorOverride[0]*255.0f; client->ps.customRGBA[1] = colorOverride[1]*255.0f; client->ps.customRGBA[2] = colorOverride[2]*255.0f; } } ClientSpawn() After client->ps.customRGBA[3]=255; Add //update our customRGBA for team colors. if ( g_gametype.integer >= GT_TEAM && g_gametype.integer != GT_SIEGE && !g_trueJedi.integer ) { char skin[MAX_QPATH]; char model[MAX_QPATH]; float colorOverride[3]; colorOverride[0] = colorOverride[1] = colorOverride[2] = 0.0f; Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); BG_ValidateSkinForTeam( model, skin, savedSess.sessionTeam, colorOverride); if (colorOverride[0] != 0.0f || colorOverride[1] != 0.0f || colorOverride[2] != 0.0f) { client->ps.customRGBA[0] = colorOverride[0]*255.0f; client->ps.customRGBA[1] = colorOverride[1]*255.0f; client->ps.customRGBA[2] = colorOverride[2]*255.0f; } } Edit: Fixed typos in first and second code sections. Link to comment Share on other sites More sharing options...
ensiform Posted September 13, 2006 Author Share Posted September 13, 2006 Also, the bug fix for item 1 in Enisform's first post doesn't fully work. It looks like currentOrigin doesn't work for spectators so you gotta do a spectator check and then return values based on that. As such, the proper fix should be.... g_cmd.c void Cmd_Where_f( gentity_t *ent ) { trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) ); } to g_cmd.c void Cmd_Where_f( gentity_t *ent ) { if(ent->client && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {//active players use currentOrigin trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->r.currentOrigin ) ) ); } else { trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) ); } } fix? spectators don't really have an origin. try playing a map with location entities in them, it doesn't update and is not supposed to. Link to comment Share on other sites More sharing options...
ensiform Posted September 13, 2006 Author Share Posted September 13, 2006 uhm... put some bots in the game from bot_minplayers, spectate them so that removerandombot will kick them however it will (try) to kick you. if you are localhost it will just say 'cannot kick localhost', also don't use ps.clientnum try something more like: int idnum; replace the top of the for loop with this: for( i = 0; i < level.numConnectedClients; i++ ) { idnum = level.sortedClients[i]; then use idnum instead of cl->ps.clientNum. then just get rid of the netname part in G_RemoveRandomBot. this is what my function looks like: /* =============== G_RemoveRandomBot =============== */ int G_RemoveRandomBot( int team ) { int i,idnum; gentity_t *cl_ent; for ( i=0 ; i< g_maxclients.integer ; i++ ) { idnum = level.sortedSlots[i]; cl_ent = g_entities + idnum; if ( cl_ent->client->pers.connected != CON_CONNECTED ) { continue; } if ( !(cl_ent->r.svFlags & SVF_BOT) ) { continue; } if ( cl_ent->client->ps.powerups[PW_BLUEFLAG] ) { continue; } if ( cl_ent->client->ps.powerups[PW_REDFLAG] ) { continue; } if ( cl_ent->client->ps.powerups[PW_NEUTRALFLAG] ) { continue; } //[bugFix9] if ( cl_ent->client->sess.sessionTeam == TEAM_SPECTATOR && cl_ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {//this entity is actually following another entity so the ps data is for a //different entity. Bots never spectate like this so, skip this player. continue; } //[/bugFix9] if (g_gametype.integer == GT_SIEGE) { if ( team >= 0 && cl_ent->client->sess.siegeDesiredTeam != team ) { continue; } } else { if ( team >= 0 && cl_ent->client->sess.sessionTeam != team ) { continue; } } trap_SendConsoleCommand( EXEC_INSERT, va2("clientkick \"%d\"\n", idnum)); return qtrue; } return qfalse; } sortedSlots is basically just sortedClients except it sorts by clientnumber instead of score, and va2 is just va but improved/tweaked. my func also skips removing bots that carry flags. Link to comment Share on other sites More sharing options...
razorace Posted September 13, 2006 Share Posted September 13, 2006 fix? spectators don't really have an origin. try playing a map with location entities in them, it doesn't update and is not supposed to. The original intent of the "where" command appears to have been for using spectator mode to determine positions on the map. That's why it doesn't work for active players. But on the flip side, currentOrigin isn't updated for spectators! Link to comment Share on other sites More sharing options...
ensiform Posted September 13, 2006 Author Share Posted September 13, 2006 /viewpos on the client. Link to comment Share on other sites More sharing options...
razorace Posted September 13, 2006 Share Posted September 13, 2006 So, "where" is the server side equivilient. I suppose they're a little different due to the view position not being the same as the model origin. Link to comment Share on other sites More sharing options...
razorace Posted September 13, 2006 Share Posted September 13, 2006 Say, for the "remapShader" exploit fix, why isn't the third argument protected as well? Is it not possible to overflow that one? Link to comment Share on other sites More sharing options...
ensiform Posted September 14, 2006 Author Share Posted September 14, 2006 ¿? hmm you mean in the trap call? well technically, i just looked at re.RemapShader in the engine and only the first parameter really needs it and the last object is really just a float as far as i can see. See (this is the fixed version in the engine using a fail-safe checker for COM_StripExtension): tr_shader.c: void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) { char strippedName[MAX_QPATH]; int hash; shader_t *sh, *sh2; qhandle_t h; sh = R_FindShaderByName( shaderName ); if (sh == NULL || sh == tr.defaultShader) { h = RE_RegisterShaderLightMap(shaderName, 0); sh = R_GetShaderByHandle(h); } if (sh == NULL || sh == tr.defaultShader) { ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName ); return; } sh2 = R_FindShaderByName( newShaderName ); if (sh2 == NULL || sh2 == tr.defaultShader) { h = RE_RegisterShaderLightMap(newShaderName, 0); sh2 = R_GetShaderByHandle(h); } if (sh2 == NULL || sh2 == tr.defaultShader) { ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName ); return; } // remap all the shaders with the given name // even tho they might have different lightmaps COM_StripExtension(shaderName, strippedName, sizeof(strippedName)); hash = generateHashValue(strippedName, FILE_HASH_SIZE); for (sh = hashTable[hash]; sh; sh = sh->next) { if (Q_stricmp(sh->name, strippedName) == 0) { if (sh != sh2) { sh->remappedShader = sh2; } else { sh->remappedShader = NULL; } } } if (timeOffset) { sh2->timeOffset = atof(timeOffset); } } old version that exists in jka: void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) { char strippedName[MAX_QPATH]; int hash; shader_t *sh, *sh2; qhandle_t h; sh = R_FindShaderByName( shaderName ); if (sh == NULL || sh == tr.defaultShader) { h = RE_RegisterShaderLightMap(shaderName, 0); sh = R_GetShaderByHandle(h); } if (sh == NULL || sh == tr.defaultShader) { ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName ); return; } sh2 = R_FindShaderByName( newShaderName ); if (sh2 == NULL || sh2 == tr.defaultShader) { h = RE_RegisterShaderLightMap(newShaderName, 0); sh2 = R_GetShaderByHandle(h); } if (sh2 == NULL || sh2 == tr.defaultShader) { ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName ); return; } // remap all the shaders with the given name // even tho they might have different lightmaps COM_StripExtension(shaderName, strippedName); hash = generateHashValue(shaderName, FILE_HASH_SIZE); for (sh = hashTable[hash]; sh; sh = sh->next) { if (Q_stricmp(sh->name, strippedName) == 0) { if (sh != sh2) { sh->remappedShader = sh2; } else { sh->remappedShader = NULL; } } } if (timeOffset) { sh2->timeOffset = atof(timeOffset); } } note how in the fixed version com_stripextension takes into affect the newsize, and the jka one does not. /* ============ COM_StripExtension ============ */ void COM_StripExtension( const char *in, char *out ) { while ( *in && *in != '.' ) { *out++ = *in++; } *out = 0; } vs. /* ============ COM_StripExtensionSafe ============ */ void COM_StripExtensionSafe( const char *in, char *out, int destsize ) { int length; Q_strncpyz(out, in, destsize); length = strlen(out)-1; while (length > 0 && out[length] != '.') { length--; if (out[length] == '/') return; // no extension } if (length) out[length] = 0; } i renamed it because i do not like to modify anything in the q_* files Link to comment Share on other sites More sharing options...
razorace Posted September 17, 2006 Share Posted September 17, 2006 There's a few typo bugs in the saberMoveData table that result in the wrong animations being played during bottom left/right broken parries, parries, and knockaways. bg_saber.c, saberMoveData[] Replace // Broken parries {"BParry Top", BOTH_H1_S1_T_, Q_T, Q_B, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UP, {"BParry UR", BOTH_H1_S1_TR, Q_TR, Q_BL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UR, {"BParry UL", BOTH_H1_S1_TL, Q_TL, Q_BR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UL, {"BParry LR", BOTH_H1_S1_BL, Q_BL, Q_TR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LR, {"BParry Bot", BOTH_H1_S1_B_, Q_B, Q_T, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LL {"BParry LL", BOTH_H1_S1_BR, Q_BR, Q_TL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LL // Knockaways {"Knock Top", BOTH_K1_S1_T_, Q_R, Q_T, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_T1_T__BR, 150 }, // LS_PARRY_UP, {"Knock UR", BOTH_K1_S1_TR, Q_R, Q_TR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_T1_TR__R, 150 }, // LS_PARRY_UR, {"Knock UL", BOTH_K1_S1_TL, Q_R, Q_TL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BR2TL, LS_T1_TL__L, 150 }, // LS_PARRY_UL, {"Knock LR", BOTH_K1_S1_BL, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_T1_BL_TL, 150 }, // LS_PARRY_LR, {"Knock LL", BOTH_K1_S1_BR, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_T1_BR_TR, 150 }, // LS_PARRY_LL // Parry {"Parry Top", BOTH_P1_S1_T_, Q_R, Q_T, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_A_T2B, 150 }, // LS_PARRY_UP, {"Parry UR", BOTH_P1_S1_TR, Q_R, Q_TL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_A_TR2BL, 150 }, // LS_PARRY_UR, {"Parry UL", BOTH_P1_S1_TL, Q_R, Q_TR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BR2TL, LS_A_TL2BR, 150 }, // LS_PARRY_UL, {"Parry LR", BOTH_P1_S1_BL, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_A_BR2TL, 150 }, // LS_PARRY_LR, {"Parry LL", BOTH_P1_S1_BR, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_A_BL2TR, 150 }, // LS_PARRY_LL with // Broken parries {"BParry Top", BOTH_H1_S1_T_, Q_T, Q_B, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UP, {"BParry UR", BOTH_H1_S1_TR, Q_TR, Q_BL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UR, {"BParry UL", BOTH_H1_S1_TL, Q_TL, Q_BR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UL, {"BParry LR", BOTH_H1_S1_BR, Q_BL, Q_TR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LR, {"BParry Bot", BOTH_H1_S1_B_, Q_B, Q_T, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LR {"BParry LL", BOTH_H1_S1_BL, Q_BR, Q_TL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LL // Knockaways {"Knock Top", BOTH_K1_S1_T_, Q_R, Q_T, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_T1_T__BR, 150 }, // LS_PARRY_UP, {"Knock UR", BOTH_K1_S1_TR, Q_R, Q_TR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_T1_TR__R, 150 }, // LS_PARRY_UR, {"Knock UL", BOTH_K1_S1_TL, Q_R, Q_TL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BR2TL, LS_T1_TL__L, 150 }, // LS_PARRY_UL, {"Knock LR", BOTH_K1_S1_BR, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_T1_BL_TL, 150 }, // LS_PARRY_LR, {"Knock LL", BOTH_K1_S1_BL, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_T1_BR_TR, 150 }, // LS_PARRY_LL // Parry {"Parry Top", BOTH_P1_S1_T_, Q_R, Q_T, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_A_T2B, 150 }, // LS_PARRY_UP, {"Parry UR", BOTH_P1_S1_TR, Q_R, Q_TL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_A_TR2BL, 150 }, // LS_PARRY_UR, {"Parry UL", BOTH_P1_S1_TL, Q_R, Q_TR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BR2TL, LS_A_TL2BR, 150 }, // LS_PARRY_UL, {"Parry LR", BOTH_P1_S1_BR, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_A_BR2TL, 150 }, // LS_PARRY_LR, {"Parry LL", BOTH_P1_S1_BL, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_A_BL2TR, 150 }, // LS_PARRY_LL Link to comment Share on other sites More sharing options...
ensiform Posted September 20, 2006 Author Share Posted September 20, 2006 Replacement for DeathmatchScoreboardMessage that comes from Enemy Territory with some enhancements and such so that it will not go over 1022 limit. Note: if you use unlagged change the ping part to use pers.realPing instead of ps.ping. // G_SendScore_Add // // Add score with clientNum at index i of level.sortedClients[] // to the string buf. // // returns qtrue if the score was appended to buf, qfalse otherwise. qboolean G_SendScore_Add(gentity_t *ent, int i, char *buf, int bufsize) { gclient_t *cl; int ping, scoreFlags=0, accuracy, perfect; char entry[256]; entry[0] = '\0'; cl = &level.clients[level.sortedClients[i]]; if ( cl->pers.connected == CON_CONNECTING ) { ping = -1; } else { ping = cl->ps.ping < 999 ? cl->ps.ping : 999; } if( cl->accuracy_shots ) { accuracy = cl->accuracy_hits * 100 / cl->accuracy_shots; } else { accuracy = 0; } perfect = ( cl->ps.persistant[PERS_RANK] == 0 && cl->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0; Com_sprintf (entry, sizeof(entry), " %i %i %i %i %i %i %i %i %i %i %i %i %i %i ", level.sortedClients[i], cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000, scoreFlags, g_entities[level.sortedClients[i]].s.powerups, accuracy, cl->ps.persistant[PERS_IMPRESSIVE_COUNT], cl->ps.persistant[PERS_EXCELLENT_COUNT], cl->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], cl->ps.persistant[PERS_DEFEND_COUNT], cl->ps.persistant[PERS_ASSIST_COUNT], perfect, cl->ps.persistant[PERS_CAPTURES]); if((strlen(buf) + strlen(entry) + 1) > bufsize) { return qfalse; } Q_strcat(buf, bufsize, entry); return qtrue; } /* ================== G_SendScore ================== */ void G_SendScore( gentity_t *ent ) { int i; int numSorted; int count; // tjw: commands over 1022 will crash the client so they're // pruned in trap_SendServerCommand() // 1022 -32 for the startbuffer char buffer[990]; char startbuffer[32]; numSorted = level.numConnectedClients; if (numSorted > MAX_CLIENTS) { numSorted = MAX_CLIENTS; } count = 0; *buffer = '\0'; *startbuffer = '\0'; Q_strncpyz(startbuffer, va( "scores %i %i %i", level.numConnectedClients, level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE]), sizeof(startbuffer)); // tjw: keep adding scores to the scores command until we fill // up the buffer. for(i=0 ; i < numSorted ; i++) { // tjw: the old version of SendScore() did this. I removed it // originally because it seemed like an unneccessary hack. // perhaps it is necessary for compat with CG_Argv()? if(!G_SendScore_Add(ent, i, buffer, sizeof(buffer))) { break; } count++; } if(!count) { return; } trap_SendServerCommand(ent-g_entities, va( "%s%s", startbuffer, buffer)); } Now just replace all instances of DeathmatchScoreboardMessage with G_SendScore. Client-Side fix to allow actually up to MAX_CLIENTS instead of only 20 clients to draw on scoreboard: cg_servercmds.c: /* ================= CG_ParseScores ================= */ static void CG_ParseScores( void ) { int i, powerups; cg.numScores = atoi( CG_Argv( 1 ) ); if ( cg.numScores > MAX_CLIENTS ) { cg.numScores = MAX_CLIENTS; } cg.teamScores[0] = atoi( CG_Argv( 2 ) ); cg.teamScores[1] = atoi( CG_Argv( 3 ) ); memset( cg.scores, 0, sizeof( cg.scores ) ); for ( i = 0 ; i < cg.numScores ; i++ ) { // cg.scores[i].client = atoi( CG_Argv( i * 14 + 4 ) ); cg.scores[i].score = atoi( CG_Argv( i * 14 + 5 ) ); cg.scores[i].ping = atoi( CG_Argv( i * 14 + 6 ) ); cg.scores[i].time = atoi( CG_Argv( i * 14 + 7 ) ); cg.scores[i].scoreFlags = atoi( CG_Argv( i * 14 + 8 ) ); powerups = atoi( CG_Argv( i * 14 + 9 ) ); cg.scores[i].accuracy = atoi(CG_Argv(i * 14 + 10)); cg.scores[i].impressiveCount = atoi(CG_Argv(i * 14 + 11)); cg.scores[i].excellentCount = atoi(CG_Argv(i * 14 + 12)); cg.scores[i].guantletCount = atoi(CG_Argv(i * 14 + 13)); cg.scores[i].defendCount = atoi(CG_Argv(i * 14 + 14)); cg.scores[i].assistCount = atoi(CG_Argv(i * 14 + 15)); cg.scores[i].perfect = atoi(CG_Argv(i * 14 + 16)); cg.scores[i].captures = atoi(CG_Argv(i * 14 + 17)); if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) { cg.scores[i].client = 0; } cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score; cgs.clientinfo[ cg.scores[i].client ].powerups = powerups; cg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team; } } Link to comment Share on other sites More sharing options...
ensiform Posted September 20, 2006 Author Share Posted September 20, 2006 Now for an updated TeamplayInfoMessage. This is going to be slightly longer because we need to add a new sorted client list to level_locals add this to level_locals_t struct (g_local.h): int sortedSlots[MAX_CLIENTS]; // sorted by clientnum now above CalculateRanks add this function (g_main.c): /* ============= SortSlots ============= */ int QDECL SortSlots( const void *a, const void *b ) { return *(int *)a - *(int *)b; } Okay now in CalculateRanks, below this line: level.sortedClients[level.numConnectedClients] = i; add: level.sortedSlots[level.numConnectedClients] = i; now look for this line: qsort( level.sortedClients, level.numConnectedClients, sizeof(level.sortedClients[0]), SortRanks ); below it add: qsort( level.sortedSlots, level.numConnectedClients, sizeof(level.sortedSlots[0]), SortSlots ); now g_team.c A replacement for TeamplayInfoMessage. // G_SendTeamInfo_Add // // Add teaminfo with clientNum at index i of level.sortedSlots[] // to the string buf. // // returns qtrue if the info was appended to buf, qfalse otherwise. qboolean G_SendTeamInfo_Add(gentity_t *ent, gentity_t *player, int idnum, char *buf, int bufsize) { int h, a; char entry[128]; entry[0] = '\0'; h = player->client->ps.stats[sTAT_HEALTH]; a = player->client->ps.stats[sTAT_ARMOR]; if (h < 0) h = 0; if (a < 0) a = 0; Com_sprintf (entry, sizeof(entry), " %i %i %i %i %i %i", idnum, player->client->pers.teamState.location, h, a, player->client->ps.weapon, player->s.powerups); if((strlen(buf) + strlen(entry) + 1) > bufsize) { return qfalse; } Q_strcat(buf, bufsize, entry); return qtrue; } /* ================== G_SendTeamInfo ================== */ void G_SendTeamInfo( gentity_t *ent ) { int i, idnum; int numSorted; int count; gentity_t *player = NULL; // tjw: commands over 1022 will crash the client so they're // pruned in trap_SendServerCommand() // 1022 -32 for the startbuffer char buffer[990]; char startbuffer[32]; if ( !ent->client->pers.teamInfo ) return; numSorted = level.numConnectedClients; if (numSorted > MAX_CLIENTS) { numSorted = MAX_CLIENTS; } count = 0; *buffer = '\0'; *startbuffer = '\0'; // tjw: keep adding teaminfos to the tinfo command until we fill // up the buffer. for(i=0 ; i < numSorted && count < TEAM_MAXOVERLAY; i++) { // tjw: the old version of SendScore() did this. I removed it // originally because it seemed like an unneccessary hack. // perhaps it is necessary for compat with CG_Argv()? idnum = level.sortedSlots[i]; player = g_entities + idnum; if ( !player->inuse || player->client->sess.sessionTeam != ent->client->sess.sessionTeam ) continue; if(!G_SendTeamInfo_Add(ent, player, idnum, buffer, sizeof(buffer))) { break; } count++; } if(!count) { return; } Q_strncpyz(startbuffer, va( "tinfo %i", count), sizeof(startbuffer)); trap_SendServerCommand(ent-g_entities, va( "%s%s", startbuffer, buffer)); } Now just replace any instances of TeamplayInfoMessage with G_SendTeamInfo. Link to comment Share on other sites More sharing options...
ensiform Posted September 20, 2006 Author Share Posted September 20, 2006 Okay, here is a good vsnprintf that works (maybe not for mac but you will have to check) for jka since you dont use qvm: q_shared.c (somewhere above Com_sprintf preferably): (comes from idStr::vsnPrintf from Str.c and Str.h from D3/Q4 1.3 SDK) /* ============ Q_vsnprintf vsnprintf portability: C99 standard: vsnprintf returns the number of characters (excluding the trailing '\0') which would have been written to the final string if enough space had been available snprintf and vsnprintf do not write more than size bytes (including the trailing '\0') win32: _vsnprintf returns the number of characters written, not including the terminating null character, or a negative value if an output error occurs. If the number of characters to write exceeds count, then count characters are written and -1 is returned and no trailing '\0' is added. Q_vsnprintf: always appends a trailing '\0', returns number of characters written (not including terminal \0) or returns -1 on failure or if the buffer would be overflowed. ============ */ int Q_vsnprintf( char *dest, int size, const char *fmt, va_list argptr ) { int ret; #ifdef _WIN32 ret = _vsnprintf( dest, size-1, fmt, argptr ); #else ret = vsnprintf( dest, size, fmt, argptr ); #endif dest[size-1] = '\0'; if ( ret < 0 || ret >= size ) { return -1; } return ret; } q_shared.h look for this code: // strlen that discounts Quake color sequences int Q_PrintStrlen( const char *string ); // removes color sequences from string char *Q_CleanStr( char *string ); add this below it: int Q_vsnprintf( char *dest, int size, const char *fmt, va_list argptr ); Use this for many things like, G_Printf, G_LogPrintf, G_Error, CG_Printf, and CG_Error that use vsprintf. However, leave va, and if you wish to use a cleaner Com_sprintf try something like this: (comes from Enemy Territory) void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { int ret; va_list argptr; va_start (argptr,fmt); ret = Q_vsnprintf (dest, size, fmt, argptr); va_end (argptr); if (ret == -1) { Com_Printf ("Com_sprintf: overflow of %i bytes buffer\n", size); } } My updated G_LogPrintf with the time fix also: /* ================= G_LogPrintf Print to the logfile with a time stamp if it is open ================= */ void QDECL G_LogPrintf( const char *fmt, ... ) { va_list argptr; char string[1024]; int mins, seconds, msec, l; msec = level.time; seconds = msec / 1000; mins = seconds / 60; seconds %= 60; msec %= 1000; Com_sprintf( string, sizeof(string), "%i:%02i ", mins, seconds ); l = strlen( string ); va_start( argptr, fmt ); Q_vsnprintf( string + l, sizeof( string ) - l, fmt, argptr ); va_end( argptr ); if ( g_dedicated.integer ) { G_Printf( "%s", string + l ); } if ( !level.logFile ) { return; } trap_FS_Write( string, strlen( string ), level.logFile ); } Link to comment Share on other sites More sharing options...
ensiform Posted September 30, 2006 Author Share Posted September 30, 2006 possibly giving ammo to incorrect index in cg_predict.c. Scroll to bottom of CG_TouchItem in cg_predict.c replace these lines: if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) { cg.predictedPlayerState.ammo[ item->giTag ] = 1; with: if ( !cg.predictedPlayerState.ammo[ weaponData[item->giTag].ammoIndex ] ) { cg.predictedPlayerState.ammo[ weaponData[item->giTag].ammoIndex ] = 1; Link to comment Share on other sites More sharing options...
ensiform Posted December 2, 2006 Author Share Posted December 2, 2006 I've just found out that Slider's fix posted on a previous page in this thread about detpacks and siege objectives when a player changes teams/disconnects does not entirely work. I've tested it and it still seems to cause them to damage the objectives. Better solution: Remove all detpacks, trip mines, and thermals from the player who switches teams or disconnects/reconnects. Also: BugFix13 is only part of the problem with the siege bridge lame, a properly placed player or other objects can still block the bridge and make it go back in. Fix: in SP_func_door make ent->spawnflags be 5 (start_open and crusher) for that mover and set ent->damage to 9999 if it is on mp/siege_hoth and is func_door and has an ent->target of "droptheclip". Link to comment Share on other sites More sharing options...
razorace Posted December 2, 2006 Share Posted December 2, 2006 That's strange, I thought my fix made it so that the mover just instantly kills anything blocking it if it gets jammed... Link to comment Share on other sites More sharing options...
ensiform Posted December 2, 2006 Author Share Posted December 2, 2006 Well I just looked and that specific mover itself is not set to be a crusher or do damage so it really wouldn't do much to players. Link to comment Share on other sites More sharing options...
razorace Posted December 3, 2006 Share Posted December 3, 2006 Point taken. Go ahead and impliment it for OJP if you want. Link to comment Share on other sites More sharing options...
ensiform Posted December 3, 2006 Author Share Posted December 3, 2006 Will do I may implement my other fix for the detpacks/trips/thermals and a person changing teams or leaving server if that is alright with you. Link to comment Share on other sites More sharing options...
razorace Posted December 3, 2006 Share Posted December 3, 2006 Sure, go ahead. You don't need pre-approval for minor bugfixes. I just mainly want to know about things that majorly rewrite gameplay/code beforehand. Link to comment Share on other sites More sharing options...
zERoCooL2479 Posted December 22, 2006 Share Posted December 22, 2006 In ai_main.c, replace if (InFieldOfVision(bs->viewangles, 100, e_ang_vec)) { //Our enemy has his saber holstered and has challenged us to a duel, so challenge him back if (!bs->cur_ps.saberHolstered) { Cmd_ToggleSaber_f(&g_entities[bs->client]); } else { if (bs->currentEnemy->client->ps.duelIndex == bs->client && bs->currentEnemy->client->ps.duelTime > level.time && !bs->cur_ps.duelInProgress) { Cmd_EngageDuel_f(&g_entities[bs->client]); } } with: if (InFieldOfVision(bs->viewangles, 100, e_ang_vec) && !bs->cur_ps.duelInProgress && !bs->currentEnemy->client->ps.fd.forcePowersActive ) { //Our enemy has his saber holstered and has challenged us to a duel, so challenge him back if (!bs->cur_ps.saberHolstered && !bs->cur_ps.saberInFlight ) { Cmd_ToggleSaber_f(&g_entities[bs->client]); } else { if (bs->currentEnemy->client->ps.duelIndex == bs->client && bs->currentEnemy->client->ps.duelTime > level.time && !bs->cur_ps.duelInProgress) { Cmd_EngageDuel_f(&g_entities[bs->client]); } } This will prevent people from laming the bots when they have their guard down. Link to comment Share on other sites More sharing options...
Soh Raun Posted January 7, 2007 Share Posted January 7, 2007 This is my first post here, but I've been reading this forum for a while and this thread was very useful to me while programming my mod, so it's time for me to contribute too I have finally fixed the "speeder lag" bug ensiform talked about earlier in this thread (well, I think this is the same bug - and if it is, the code he provided didn't fix it). Here is exactly when it happens: you're for example the client 1, and you're a spectator following the client 0. The client 0 fires an event (like attacking, or jumping on a vehicle..) while you're watching him. You stop following him. He climbs on a vehicle, and this is when the bug happen: your view begins to shake/lag horribly when this player is in view (or almost) and on the vehicle. As soon as he gets off, your view comes back to normal. The problem is client-side, and here is the reason: while you are following someone, you receive his events, which calls CG_CheckPlayerstateEvents with the address of cg.snap->ps in the first argument. So the "cent->playerState = ps;" line of this function replaces the cent's (here, client 0) playerState ADDRESS (which should always be in the cgSendPSPool array) with the ADDRESS of the snapshot's playerState. Now you can imagine what happens in CG_Player when the client 0 is attached to the vehicle: his playerState->origin is changed, which also changes the cg.snap->ps.origin, and your view is moved when it shouldn't. It's shaky simply because the cg.snap is alternatively in cg.activeSnapshots[0] and in cg.activeSnapshots[1], so sometimes the snapshot is not modified and the origin is correct. To make it short: in cg_playerState.c in CG_CheckPlayerstateEvents, comment the line 242: void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) { ... //JLF ADDED to hopefully mark events as player event //cent->playerState = ps; ... } I think it's ok to simply comment it, because it seems completely stupid, and the comment above (//JLF ADDED to hopefully mark events as player event) shows it was probably meant to be used on Xbox only (the JLF comments are often related to Xbox stuff). I didn't notice anything weird after commenting it, anyway. Sorry for the long explanation for a so simple bugfix (1 line to comment, but it took me hours to find it), but I don't think it was obvious it was related to the bug described Link to comment Share on other sites More sharing options...
ensiform Posted January 7, 2007 Author Share Posted January 7, 2007 This is an interesting theory, and I really didn't think mine was going to fix it in the first place, though it does force spectators off that vehicle it still isn't right. Good find Soh Raun. Link to comment Share on other sites More sharing options...
razorace Posted January 7, 2007 Share Posted January 7, 2007 Nice find Sol Raun. Welcome to the community. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.