From 1b30b072cdaaec373500444f404317dd68b90982 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 15 Apr 2018 12:10:22 -0500 Subject: [PATCH 01/42] mint-arena: Move FIGHT message to match VQ3 in non-splitscreen --- code/cgame/cg_servercmds.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/cgame/cg_servercmds.c b/code/cgame/cg_servercmds.c index 0de688a95..8aa1f4ddf 100644 --- a/code/cgame/cg_servercmds.c +++ b/code/cgame/cg_servercmds.c @@ -580,7 +580,11 @@ static void CG_MapRestart( void ) { // play the "fight" sound if this is a restart without warmup if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) { trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER ); - CG_GlobalCenterPrint( "FIGHT!", SCREEN_HEIGHT/2, 2.0 ); + if ( CG_NumLocalPlayers() > 1 ) { + CG_GlobalCenterPrint( "FIGHT!", SCREEN_HEIGHT/2, 2.0 ); + } else { + CG_GlobalCenterPrint( "FIGHT!", 112 + GIANTCHAR_HEIGHT/2, 2.0 ); + } } #ifdef MISSIONPACK if (cg_singlePlayer.integer) { From ada730875bcdd1283130910839b6c831745411c7 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sat, 21 Apr 2018 12:37:19 -0500 Subject: [PATCH 02/42] mint-arena: Initialize botimport.MilliSeconds I added it for sharing code with BSPC but I forgot to initialize it in the Game VM. --- code/game/ai_chat_sys.c | 12 ++++++------ code/game/g_botlib.c | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/code/game/ai_chat_sys.c b/code/game/ai_chat_sys.c index 89601cceb..7bf7fa4e2 100644 --- a/code/game/ai_chat_sys.c +++ b/code/game/ai_chat_sys.c @@ -1051,7 +1051,7 @@ bot_randomlist_t *BotLoadRandomStrings(char *filename) bot_randomstring_t *randomstring; #ifdef DEBUG - int starttime = Sys_MilliSeconds(); + int starttime = botimport.MilliSeconds(); #endif //DEBUG if ( !*filename ) @@ -1138,7 +1138,7 @@ bot_randomlist_t *BotLoadRandomStrings(char *filename) BotAI_Print(PRT_DEVELOPER, "loaded %s\n", filename); // #ifdef DEBUG - BotAI_Print(PRT_DEVELOPER, "random strings %d msec\n", Sys_MilliSeconds() - starttime); + BotAI_Print(PRT_DEVELOPER, "random strings %d msec\n", botimport.MilliSeconds() - starttime); //BotDumpRandomStringList(randomlist); #endif //DEBUG // @@ -2174,7 +2174,7 @@ bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname) #ifdef DEBUG int starttime; - starttime = Sys_MilliSeconds(); + starttime = botimport.MilliSeconds(); #endif //DEBUG // size = 0; @@ -2322,7 +2322,7 @@ bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname) BotCheckInitialChatIntegrety(chat); } //end if #ifdef DEBUG - BotAI_Print(PRT_DEVELOPER, "initial chats loaded in %d msec\n", Sys_MilliSeconds() - starttime); + BotAI_Print(PRT_DEVELOPER, "initial chats loaded in %d msec\n", botimport.MilliSeconds() - starttime); #endif //DEBUG //character was read successfully return chat; @@ -3098,7 +3098,7 @@ void BotFreeChatState(int handle) int BotSetupChatAI(void) { #ifdef DEBUG - int starttime = Sys_MilliSeconds(); + int starttime = botimport.MilliSeconds(); #endif //DEBUG synonyms = BotLoadSynonyms("syn.c"); @@ -3113,7 +3113,7 @@ int BotSetupChatAI(void) InitConsoleMessageHeap(); #ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "setup chat AI %d msec\n", Sys_MilliSeconds() - starttime); + BotAI_Print(PRT_MESSAGE, "setup chat AI %d msec\n", botimport.MilliSeconds() - starttime); #endif //DEBUG return BLERR_NOERROR; } //end of the function BotSetupChatAI diff --git a/code/game/g_botlib.c b/code/game/g_botlib.c index 0b385c611..f665c3565 100644 --- a/code/game/g_botlib.c +++ b/code/game/g_botlib.c @@ -108,6 +108,7 @@ G_BotInitBotLib void G_BotInitBotLib(void) { botlib_import_t botlib_import; + botlib_import.MilliSeconds = trap_Milliseconds; botlib_import.Print = BotAI_Print; botlib_import.Trace = BotAI_Trace; botlib_import.EntityTrace = BotAI_EntityTrace; From 824a1f6fc0f2c7d70fab7e4a8c681cb575ab0ab2 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Thu, 3 May 2018 21:18:07 -0500 Subject: [PATCH 03/42] mint-arena: Fix unable to type in console when missing missionpack menus If using missionpack UI code but missing menu scripts the console will be drawn fullscreen. However it was not possible to type in the console. --- code/cgame/cg_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index cffb81427..d2e121957 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -3100,6 +3100,9 @@ void CG_DistributeKeyEvent( int key, qboolean down, unsigned time, connstate_t s CG_KeyEvent( key, down ); } else if ( keyCatcher & KEYCATCH_UI ) { UI_KeyEvent( key, down ); + } else if ( state == CA_DISCONNECTED ) { + // console is drawn if disconnected and not KEYCATCH_UI + Console_Key( key, down ); } } @@ -3126,6 +3129,9 @@ void CG_DistributeCharEvent( int character, connstate_t state ) { CG_KeyEvent( key, qtrue ); } else if ( keyCatcher & KEYCATCH_UI ) { UI_KeyEvent( key, qtrue ); + } else if ( state == CA_DISCONNECTED ) { + // console is drawn if disconnected and not KEYCATCH_UI + Console_Key( key, qtrue ); } } From f8f504ba1973d0dfac23414fe008a2da04302ded Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Thu, 3 May 2018 21:27:55 -0500 Subject: [PATCH 04/42] mint-arena: Clear screen before drawing dedicated console The console shader may be transparent causing past frame buffer to be seen / lower performance. --- code/cgame/cg_console.c | 1 + 1 file changed, 1 insertion(+) diff --git a/code/cgame/cg_console.c b/code/cgame/cg_console.c index c751ded24..78013c5e8 100644 --- a/code/cgame/cg_console.c +++ b/code/cgame/cg_console.c @@ -393,6 +393,7 @@ void Con_DrawConsole( connstate_t state ) { // if disconnected, render console full screen if ( state == CA_DISCONNECTED ) { if ( !( Key_GetCatcher() & KEYCATCH_UI ) ) { + CG_ClearViewport(); Con_DrawSolidConsole( state, 1.0f ); return; } From a702b0395e8f62a7ba1c657e8140d5fbe424bbf8 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 6 May 2018 02:11:06 -0500 Subject: [PATCH 05/42] mint-arena: Add random bot to Team Arena UI + correct list in Game VM Add "Random Bot" to Team Arena start server and ingame addbot menus to execute command "addbot random". Team Arena's addbot menu only allows adding characters from teaminfo.txt in g_gametypes >= GT_TEAM, so use them for random bot selection for "addbot random" and "bot_minplayers". --- code/game/g_bot.c | 175 ++++++++++++++++++++++++++++++++++++++++++---- code/ui/ui_main.c | 84 +++++++++++++++------- 2 files changed, 220 insertions(+), 39 deletions(-) diff --git a/code/game/g_bot.c b/code/game/g_bot.c index 61c4e85de..fbf6bf548 100644 --- a/code/game/g_bot.c +++ b/code/game/g_bot.c @@ -36,6 +36,11 @@ Suite 120, Rockville, Maryland 20850 USA. static int g_numBots; static char *g_botInfos[MAX_BOTS]; +#ifdef MISSIONPACK +static int g_numTeamBots; +static char *g_teamBotInfos[MAX_BOTS]; +#endif + int g_numArenas; static char *g_arenaInfos[MAX_ARENAS]; @@ -268,23 +273,36 @@ G_SelectRandomBotInfo Get random least used bot info on team or whole server if team is -1. =============== */ -int G_SelectRandomBotInfo( int team ) { +char *G_SelectRandomBotInfo( int team ) { int selection[MAX_BOTS]; int n, num; int count, bestCount; char *value; + int numBots; + char **botInfos; + +#ifdef MISSIONPACK + if ( g_gametype.integer >= GT_TEAM ) { + numBots = g_numTeamBots; + botInfos = g_teamBotInfos; + } else +#endif + { + numBots = g_numBots; + botInfos = g_botInfos; + } // don't add duplicate bots to the server if there are less bots than bot types - if ( team != -1 && G_CountBotPlayersByName( NULL, -1 ) < g_numBots ) { + if ( team != -1 && G_CountBotPlayersByName( NULL, -1 ) < numBots ) { team = -1; } num = 0; bestCount = MAX_CLIENTS; - for ( n = 0; n < g_numBots ; n++ ) { - value = Info_ValueForKey( g_botInfos[n], "funname" ); + for ( n = 0; n < numBots ; n++ ) { + value = Info_ValueForKey( botInfos[n], "funname" ); if ( !value[0] ) { - value = Info_ValueForKey( g_botInfos[n], "name" ); + value = Info_ValueForKey( botInfos[n], "name" ); } // count = G_CountBotPlayersByName( value, team ); @@ -305,10 +323,10 @@ int G_SelectRandomBotInfo( int team ) { if ( num > 0 ) { num = random() * ( num - 1 ); - return selection[num]; + return botInfos[selection[num]]; } - return -1; + return NULL; } /* @@ -607,7 +625,6 @@ static void G_AddBot( const char *name, float skill, const char *team, int delay int connectionNum; int playerNum; int teamNum; - int botinfoNum; char *botinfo; char *key; char *s; @@ -659,15 +676,13 @@ static void G_AddBot( const char *name, float skill, const char *team, int delay teamNum = TEAM_FREE; } - botinfoNum = G_SelectRandomBotInfo( teamNum ); + botinfo = G_SelectRandomBotInfo( teamNum ); - if ( botinfoNum < 0 ) { + if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Cannot add random bot, no bot info available.\n" ); trap_BotFreeClient( playerNum ); return; } - - botinfo = G_GetBotInfoByNumber( botinfoNum ); } else { botinfo = G_GetBotInfoByName( name ); @@ -1026,6 +1041,139 @@ char *G_GetBotInfoByName( const char *name ) { return NULL; } +#ifdef MISSIONPACK +/* +=============== +Character_Parse +=============== +*/ +static qboolean Character_Parse(char **p, const char *filename) { + char *token; + char name[MAX_NAME_LENGTH]; + + token = COM_ParseExt(p, qtrue); + + if ( token[0] != '{' ) { + return qfalse; + } + + while ( 1 ) { + token = COM_ParseExt(p, qtrue); + + if (Q_stricmp(token, "}") == 0) { + return qtrue; + } + + if (!token[0]) { + return qfalse; + } + + if (token[0] == '{') { + // two tokens per line, character name and sex + token = COM_ParseExt(p, qtrue); + if ( !token[0] ) { + return qfalse; + } + Q_strncpyz( name, token, sizeof( name ) ); + + token = COM_ParseExt(p, qtrue); + if ( !token[0] ) { + return qfalse; + } + + if ( g_numTeamBots < ARRAY_LEN( g_teamBotInfos ) ) { + g_teamBotInfos[g_numTeamBots] = G_GetBotInfoByName( name ); + if ( g_teamBotInfos[g_numTeamBots] ) { + g_numTeamBots++; + } else { + G_Printf( S_COLOR_YELLOW "WARNING: No bot defined in bots.txt for character '%s' in %s.\n", name, filename ); + } + } + + token = COM_ParseExt(p, qtrue); + if (token[0] != '}') { + return qfalse; + } + } + } + + return qfalse; +} + +/* +=============== +G_ParseTeamInfo + +Team Arena's addbot menu only allows adding characters from teaminfo.txt +in g_gametypes >= GT_TEAM, so use them for random bot selection too. +=============== +*/ +static void G_ParseTeamInfo( const char *filename ) { + int len; + fileHandle_t f; + char buf[MAX_BOTS_TEXT]; + char *p, *token; + + g_numTeamBots = 0; + + if ( g_gametype.integer < GT_TEAM ) { + return; + } + + len = trap_FS_FOpenFile( filename, &f, FS_READ ); + if ( !f ) { + trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) ); + return; + } + if ( len >= MAX_BOTS_TEXT ) { + trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_BOTS_TEXT ) ); + trap_FS_FCloseFile( f ); + return; + } + + trap_FS_Read( buf, len, f ); + buf[len] = 0; + trap_FS_FCloseFile( f ); + + p = buf; + + while ( 1 ) { + token = COM_ParseExt( &p, qtrue ); + if(!token[0] || token[0] == '}') { + break; + } + + if ( Q_stricmp( token, "}" ) == 0 ) { + break; + } + + if (Q_stricmp(token, "teams") == 0) { + if (SkipBracedSection(&p, 0)) { + continue; + } else { + break; + } + } + + if (Q_stricmp(token, "characters") == 0) { + if (Character_Parse(&p, filename)) { + continue; + } else { + break; + } + } + + if (Q_stricmp(token, "aliases") == 0) { + if (SkipBracedSection(&p, 0)) { + continue; + } else { + break; + } + } + } +} +#endif + /* =============== G_InitBots @@ -1042,6 +1190,9 @@ void G_InitBots( qboolean restart ) { G_LoadBots(); G_LoadArenas(); +#ifdef MISSIONPACK + G_ParseTeamInfo( "teaminfo.txt" ); +#endif trap_Cvar_Register( &bot_minplayers, "bot_minplayers", "0", CVAR_SERVERINFO ); diff --git a/code/ui/ui_main.c b/code/ui/ui_main.c index 15d2339c8..b7907877b 100644 --- a/code/ui/ui_main.c +++ b/code/ui/ui_main.c @@ -904,15 +904,18 @@ static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle) { // 0 - None // 1 - Human - // 2..NumCharacters - Bot + // 2 - Random Bot + // 3..NumCharacters - Bot int value = trap_Cvar_VariableValue(va(blue ? "ui_blueteam%i" : "ui_redteam%i", num)); const char *text; if (value <= 0) { text = "Closed"; } else if (value == 1) { text = "Human"; + } else if (value == 2) { + text = "Random Bot"; } else { - value -= 2; + value -= 3; if (ui_actualNetGameType.integer >= GT_TEAM) { if (value >= uiInfo.characterCount) { @@ -1431,19 +1434,17 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale) { } static void UI_DrawBotName(rectDef_t *rect, float scale, vec4_t color, int textStyle) { + // 0 - Random Bot + // 1..NumCharacters - Bot int value = uiInfo.botIndex; int game = trap_Cvar_VariableValue("g_gametype"); const char *text = ""; - if (game >= GT_TEAM) { - if (value >= uiInfo.characterCount) { - value = 0; - } - text = uiInfo.characterList[value].name; + if (value == 0) { + text = "Random Bot"; + } else if (game >= GT_TEAM) { + text = uiInfo.characterList[value-1].name; } else { - if (value >= UI_GetNumBots()) { - value = 0; - } - text = UI_GetBotNameByNumber(value); + text = UI_GetBotNameByNumber(value-1); } UI_Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle); } @@ -2100,23 +2101,24 @@ static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboo if (select != 0) { // 0 - None // 1 - Human - // 2..NumCharacters - Bot + // 2 - Random Bot + // 3..NumCharacters - Bot char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num); int value = trap_Cvar_VariableValue(cvar); value += select; if (ui_actualNetGameType.integer >= GT_TEAM) { - if (value >= uiInfo.characterCount + 2) { + if (value >= uiInfo.characterCount + 3) { value = 0; } else if (value < 0) { - value = uiInfo.characterCount + 2 - 1; + value = uiInfo.characterCount + 3 - 1; } } else { - if (value >= UI_GetNumBots() + 2) { + if (value >= UI_GetNumBots() + 3) { value = 0; } else if (value < 0) { - value = UI_GetNumBots() + 2 - 1; + value = UI_GetNumBots() + 3 - 1; } } @@ -2194,22 +2196,24 @@ static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) { static qboolean UI_BotName_HandleKey(int flags, float *special, int key) { int select = UI_SelectForKey(key); if (select != 0) { + // 0 - Random Bot + // 1..NumCharacters - Bot int game = trap_Cvar_VariableValue("g_gametype"); int value = uiInfo.botIndex; value += select; if (game >= GT_TEAM) { - if (value >= uiInfo.characterCount + 2) { + if (value >= uiInfo.characterCount + 1) { value = 0; } else if (value < 0) { - value = uiInfo.characterCount + 2 - 1; + value = uiInfo.characterCount + 1 - 1; } } else { - if (value >= UI_GetNumBots() + 2) { + if (value >= UI_GetNumBots() + 1) { value = 0; } else if (value < 0) { - value = UI_GetNumBots() + 2 - 1; + value = UI_GetNumBots() + 1 - 1; } } uiInfo.botIndex = value; @@ -2859,21 +2863,41 @@ static void UI_RunMenuScript(char **args) { trap_Cvar_SetValue("sv_maxClients", clients); for (i = 0; i < PLAYERS_PER_TEAM; i++) { + // 0 - None + // 1 - Human + // 2 - Random Bot + // 3..NumCharacters - Bot int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1)); if (bot > 1) { + if (bot == 2) { + name = "random"; + } else if (ui_actualNetGameType.integer >= GT_TEAM) { + name = uiInfo.characterList[bot-3].name; + } else { + name = UI_GetBotNameByNumber(bot-3); + } + if (ui_actualNetGameType.integer >= GT_TEAM) { - Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Blue"); + Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", name, skill, "Blue"); } else { - Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill); + Com_sprintf( buff, sizeof(buff), "addbot %s %f\n", name, skill); } trap_Cmd_ExecuteText( EXEC_APPEND, buff ); } bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1)); if (bot > 1) { + if (bot == 2) { + name = "random"; + } else if (ui_actualNetGameType.integer >= GT_TEAM) { + name = uiInfo.characterList[bot-3].name; + } else { + name = UI_GetBotNameByNumber(bot-3); + } + if (ui_actualNetGameType.integer >= GT_TEAM) { - Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Red"); + Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", name, skill, "Red"); } else { - Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill); + Com_sprintf( buff, sizeof(buff), "addbot %s %f\n", name, skill); } trap_Cmd_ExecuteText( EXEC_APPEND, buff ); } @@ -3031,11 +3055,17 @@ static void UI_RunMenuScript(char **args) { trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader %s\n",uiInfo.teamPlayerNames[uiInfo.teamIndex]) ); } } else if (Q_stricmp(name, "addBot") == 0) { - if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM) { - trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", uiInfo.characterList[uiInfo.botIndex].name, uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") ); + // 0 - Random Bot + // 1..NumCharacters - Bot + if (uiInfo.botIndex == 0) { + name = "random"; + } else if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM) { + name = uiInfo.characterList[uiInfo.botIndex-1].name; } else { - trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") ); + name = UI_GetBotNameByNumber(uiInfo.botIndex-1); } + + trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", name, uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "red" : "blue") ); } else if (Q_stricmp(name, "addFavorite") == 0) { if (ui_netSource.integer != UIAS_FAVORITES) { char name[MAX_NAME_LENGTH]; From bfc2c1c372280ec80b074f45013c8579ad3c73df Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Thu, 10 May 2018 04:55:27 -0500 Subject: [PATCH 06/42] mint-arena: Update version to 0.6 for IDEs Missed updating version in bg_public.h at the same time as Makefile. --- code/game/bg_public.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/bg_public.h b/code/game/bg_public.h index 1f7b4ed90..edd482275 100644 --- a/code/game/bg_public.h +++ b/code/game/bg_public.h @@ -44,7 +44,7 @@ Suite 120, Rockville, Maryland 20850 USA. // Keep this in-sync with VERSION in Makefile. #ifndef PRODUCT_VERSION - #define PRODUCT_VERSION "0.5" + #define PRODUCT_VERSION "0.6" #endif // because games can change separately from the main system protocol, we need a From 860f759f62d9c06b9169b38ca1411525fef263c5 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sat, 12 May 2018 03:06:53 -0500 Subject: [PATCH 07/42] mint-arena: Fix spectator list and UI_NOSCALE pixel boundary alignment Fixes for "mint-arena: Don't align text in motion to pixel boundary" commit cf45c8700c54dc4c50fd690e04b96c429797cc5f (Sep 16 2017). Fix CGame scrolling spectator list to actually disable text alignment. Fix UI_INMOTION being applied to UI_NOSCALE text. --- code/cgame/cg_newdraw.c | 2 +- code/game/bg_public.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/cgame/cg_newdraw.c b/code/cgame/cg_newdraw.c index bde4f2576..82989cab9 100644 --- a/code/cgame/cg_newdraw.c +++ b/code/cgame/cg_newdraw.c @@ -110,7 +110,7 @@ void CG_Text_PaintInMotion(float x, float y, float scale, const vec4_t color, co shadowOffset = 0; } - Text_Paint( x, y, CG_FontForScale( scale ), scale, color, text, adjust, limit, shadowOffset, 0, qfalse, qfalse ); + Text_Paint( x, y, CG_FontForScale( scale ), scale, color, text, adjust, limit, shadowOffset, 0, qfalse, qtrue ); } void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, const vec4_t color, const char* text, float adjust, int limit) { diff --git a/code/game/bg_public.h b/code/game/bg_public.h index edd482275..7f6df5767 100644 --- a/code/game/bg_public.h +++ b/code/game/bg_public.h @@ -1199,7 +1199,7 @@ void SnapVectorTowards( vec3_t v, vec3_t to ); #define UI_FORCECOLOR 0x00010000 #define UI_GRADIENT 0x00020000 #define UI_NOSCALE 0x00040000 // fixed size with other UI elements, don't change it's scale -#define UI_INMOTION 0x00040000 // use for scrolling / moving text to fix uneven scrolling caused by aligning to pixel boundary +#define UI_INMOTION 0x00080000 // use for scrolling / moving text to fix uneven scrolling caused by aligning to pixel boundary typedef struct From 7f33cddac3826de6c63cbf3a62a5b79eac88ac0d Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sat, 21 Apr 2018 14:07:22 -0500 Subject: [PATCH 08/42] Fix possible bot goal state NULL pointer dereference --- code/game/ai_goal.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/game/ai_goal.c b/code/game/ai_goal.c index 5e993d67b..0c3a8996f 100644 --- a/code/game/ai_goal.c +++ b/code/game/ai_goal.c @@ -198,6 +198,9 @@ void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) p2 = BotGoalStateFromHandle(parent2); c = BotGoalStateFromHandle(child); + if (!p1 || !p2 || !c) + return; + InterbreedWeightConfigs(p1->itemweightconfig, p2->itemweightconfig, c->itemweightconfig); } //end of the function BotInterbreedingGoalFuzzyLogic @@ -212,7 +215,7 @@ void BotSaveGoalFuzzyLogic(int goalstate, char *filename) //bot_goalstate_t *gs; //gs = BotGoalStateFromHandle(goalstate); - + //if (!gs) return; //WriteWeightConfig(filename, gs->itemweightconfig); } //end of the function BotSaveGoalFuzzyLogic //=========================================================================== @@ -226,7 +229,7 @@ void BotMutateGoalFuzzyLogic(int goalstate, float range) bot_goalstate_t *gs; gs = BotGoalStateFromHandle(goalstate); - + if (!gs) return; EvolveWeightConfig(gs->itemweightconfig); } //end of the function BotMutateGoalFuzzyLogic //=========================================================================== From 8967cfff539a7ed9ef276e31a063216443376156 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sat, 21 Apr 2018 14:39:18 -0500 Subject: [PATCH 09/42] Fix uninitialized bot_goal_t fields --- code/game/ai_goal.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/code/game/ai_goal.c b/code/game/ai_goal.c index 0c3a8996f..ccaf83d9f 100644 --- a/code/game/ai_goal.c +++ b/code/game/ai_goal.c @@ -862,6 +862,7 @@ int BotGetLevelItemGoal(int index, char *name, bot_goal_t *goal) goal->number = li->number; goal->flags = GFL_ITEM; if (li->timeout) goal->flags |= GFL_DROPPED; + goal->iteminfo = li->iteminfo; //BotAI_Print(PRT_MESSAGE, "found li %s\n", itemconfig->iteminfo[li->iteminfo].name); return li->number; } //end if @@ -891,6 +892,9 @@ int BotGetMapLocationGoal(char *name, bot_goal_t *goal) goal->entitynum = 0; VectorCopy(mins, goal->mins); VectorCopy(maxs, goal->maxs); + goal->number = 0; + goal->flags = 0; + goal->iteminfo = 0; return qtrue; } //end if } //end for @@ -919,6 +923,9 @@ int BotGetNextCampSpotGoal(int num, bot_goal_t *goal) goal->entitynum = 0; VectorCopy(mins, goal->mins); VectorCopy(maxs, goal->maxs); + goal->number = 0; + goal->flags = 0; + goal->iteminfo = 0; return num+1; } //end if } //end for From 144dc866980ff91b8459af5940403cc8a6490da9 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 22 Apr 2018 17:56:43 -0500 Subject: [PATCH 10/42] Make UI_DrawProportionalString handle NULL string This makes the function consistent with UI_DrawString. --- code/q3_ui/ui_atoms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/q3_ui/ui_atoms.c b/code/q3_ui/ui_atoms.c index 0d8735674..1fc46a69e 100644 --- a/code/q3_ui/ui_atoms.c +++ b/code/q3_ui/ui_atoms.c @@ -455,6 +455,10 @@ void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t float propScale; float scale; + if( !str ) { + return; + } + propScale = UI_ProportionalSizeScale( style ); charh = propScale * PROP_HEIGHT; From c4bb37cfd2a6e42f0cea06f025a4a57e1379cea5 Mon Sep 17 00:00:00 2001 From: IR4T4 Date: Thu, 26 Apr 2018 17:52:44 +0200 Subject: [PATCH 11/42] Fix array index in CanDamage() function - discovered by MARTY The wrong array element was accessed. However the correct element is the same value so fixing it does not affect gameplay. --- code/game/g_combat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/g_combat.c b/code/game/g_combat.c index 7ca887848..96fe9b8bf 100644 --- a/code/game/g_combat.c +++ b/code/game/g_combat.c @@ -1226,7 +1226,7 @@ qboolean CanDamage (gentity_t *targ, vec3_t origin) { VectorCopy(midpoint, dest); dest[0] += offsetmins[0]; - dest[1] += offsetmins[2]; + dest[1] += offsetmins[1]; dest[2] += offsetmins[2]; trap_Trace(&tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); From 85905ce9c1436249dedd940cffee652c09cd10f4 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Thu, 26 Apr 2018 11:40:16 -0500 Subject: [PATCH 12/42] Fix clearing keys for control in Team Arena UI When a control is selected for binding a key, pressing backspace would clear the displayed keys in the menu but not actually unbind the keys. --- code/ui/ui_shared.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/code/ui/ui_shared.c b/code/ui/ui_shared.c index 29c197fca..8454a94ae 100644 --- a/code/ui/ui_shared.c +++ b/code/ui/ui_shared.c @@ -3563,8 +3563,14 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { case K_BACKSPACE: id = BindingIDFromName(item->cvar); if (id != -1) { - g_bindings[id].bind1 = -1; - g_bindings[id].bind2 = -1; + if( g_bindings[id].bind1 != -1 ) { + DC->setBinding( g_bindings[id].bind1, "" ); + g_bindings[id].bind1 = -1; + } + if( g_bindings[id].bind2 != -1 ) { + DC->setBinding( g_bindings[id].bind2, "" ); + g_bindings[id].bind2 = -1; + } } Controls_SetConfig(qtrue); g_waitingForKey = qfalse; From 68eb7b2e8b627808c29277fec1411acab5d22cdb Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 29 Apr 2018 14:28:28 -0500 Subject: [PATCH 13/42] Improvements for dedicated camera followers (team follow1/2) Switching to dedicated camera follower with no possible players to follow would spawn at the intermission point and display "connection interrupted" HUD message. Pmove() was not run for the client so ps.commandTime was too far behind. I made it so that dedicated camera followers and scoreboard run Pmove() but cannot move (PM_FREEZE). When all players possible to follow leave, the dedicated camera follower would continue to display the old player state of the player they were following (along with "connection interrupted" HUD message). Unlike the regular case of a spectator following a specific player, dedicated camera followers did not reset their player state to the intermission point after the followed player was no longer valid. Now a client can be set as 'team follow1' to automatically switch between displaying the intermission point and following a player when possible. --- code/game/g_active.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/code/game/g_active.c b/code/game/g_active.c index 69632220b..e2c329172 100644 --- a/code/game/g_active.c +++ b/code/game/g_active.c @@ -328,11 +328,15 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) { player = ent->player; - if ( player->sess.spectatorState != SPECTATOR_FOLLOW ) { - if ( player->noclip ) { - player->ps.pm_type = PM_NOCLIP; + if ( player->sess.spectatorState != SPECTATOR_FOLLOW || !( player->ps.pm_flags & PMF_FOLLOW ) ) { + if ( player->sess.spectatorState == SPECTATOR_FREE ) { + if ( player->noclip ) { + player->ps.pm_type = PM_NOCLIP; + } else { + player->ps.pm_type = PM_SPECTATOR; + } } else { - player->ps.pm_type = PM_SPECTATOR; + player->ps.pm_type = PM_FREEZE; } player->ps.speed = 400; // faster than normal @@ -1061,14 +1065,17 @@ void SpectatorPlayerEndFrame( gentity_t *ent ) { ent->player->ps.pm_flags |= PMF_FOLLOW; ent->player->ps.eFlags = flags; return; - } else { - // drop them to free spectators unless they are dedicated camera followers - if ( ent->player->sess.spectatorPlayer >= 0 ) { - ent->player->sess.spectatorState = SPECTATOR_FREE; - PlayerBegin( ent->player - level.players ); - } } } + + if ( ent->player->ps.pm_flags & PMF_FOLLOW ) { + // drop them to free spectators unless they are dedicated camera followers + if ( ent->player->sess.spectatorPlayer >= 0 ) { + ent->player->sess.spectatorState = SPECTATOR_FREE; + } + + PlayerBegin( ent->player - level.players ); + } } if ( ent->player->sess.spectatorState == SPECTATOR_SCOREBOARD ) { From 128d2edf307a70ec7a0fa577dba6a216a730153a Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sat, 12 May 2018 14:09:02 -0500 Subject: [PATCH 14/42] mint-arena: Don't compile all files with Altivec Compiling with -maltivec may generate code in VM dylibs on that will crash on non-altivec PowerPC. --- Makefile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 4e9f39fa8..9c336a1d8 100644 --- a/Makefile +++ b/Makefile @@ -228,11 +228,11 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu") HAVE_VM_COMPILED=true else ifeq ($(ARCH),ppc) - BASE_CFLAGS += -maltivec + ALTIVEC_CFLAGS = -maltivec HAVE_VM_COMPILED=true endif ifeq ($(ARCH),ppc64) - BASE_CFLAGS += -maltivec + ALTIVEC_CFLAGS = -maltivec HAVE_VM_COMPILED=true endif ifeq ($(ARCH),sparc) @@ -294,10 +294,12 @@ ifeq ($(PLATFORM),darwin) -DMAC_OS_X_VERSION_MIN_REQUIRED=$(MAC_OS_X_VERSION_MIN_REQUIRED) ifeq ($(ARCH),ppc) - BASE_CFLAGS += -arch ppc -faltivec + BASE_CFLAGS += -arch ppc + ALTIVEC_CFLAGS = -faltivec endif ifeq ($(ARCH),ppc64) - BASE_CFLAGS += -arch ppc64 -faltivec + BASE_CFLAGS += -arch ppc64 + ALTIVEC_CFLAGS = -faltivec endif ifeq ($(ARCH),x86) OPTIMIZEVM += -march=prescott -mfpmath=sse @@ -495,11 +497,11 @@ ifeq ($(PLATFORM),openbsd) HAVE_VM_COMPILED=true else ifeq ($(ARCH),ppc) - BASE_CFLAGS += -maltivec + ALTIVEC_CFLAGS = -maltivec HAVE_VM_COMPILED=true endif ifeq ($(ARCH),ppc64) - BASE_CFLAGS += -maltivec + ALTIVEC_CFLAGS = -maltivec HAVE_VM_COMPILED=true endif ifeq ($(ARCH),sparc64) From 67a71c9ec2edcbc3895ec679d8b248001262290f Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 13 May 2018 22:37:45 -0500 Subject: [PATCH 15/42] mint-arena: Use function pointers in ui_shared.c instead of CG_ Make it easier to port to projects using separate CGame and UI VMs. --- code/cgame/cg_main.c | 3 +++ code/ui/ui_main.c | 3 +++ code/ui/ui_shared.c | 8 ++++---- code/ui/ui_shared.h | 3 +++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index d2e121957..da2e8bae5 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -2499,6 +2499,9 @@ void CG_LoadHudMenu( void ) { cgDC.stopCinematic = &CG_StopCinematic; cgDC.drawCinematic = &CG_DrawCinematic; cgDC.runCinematicFrame = &CG_RunCinematicFrame; + cgDC.adjustFrom640 = &CG_AdjustFrom640; + cgDC.setScreenPlacement = &CG_SetScreenPlacement; + cgDC.popScreenPlacement = &CG_PopScreenPlacement; Init_Display(&cgDC); diff --git a/code/ui/ui_main.c b/code/ui/ui_main.c index b7907877b..032a788e4 100644 --- a/code/ui/ui_main.c +++ b/code/ui/ui_main.c @@ -4762,6 +4762,9 @@ void UI_Init( qboolean inGameLoad, int maxSplitView ) { uiInfo.uiDC.stopCinematic = &UI_StopCinematic; uiInfo.uiDC.drawCinematic = &UI_DrawCinematic; uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame; + uiInfo.uiDC.adjustFrom640 = &CG_AdjustFrom640; + uiInfo.uiDC.setScreenPlacement = &CG_SetScreenPlacement; + uiInfo.uiDC.popScreenPlacement = &CG_PopScreenPlacement; Init_Display(&uiInfo.uiDC); diff --git a/code/ui/ui_shared.c b/code/ui/ui_shared.c index 8454a94ae..202c879a3 100644 --- a/code/ui/ui_shared.c +++ b/code/ui/ui_shared.c @@ -3657,7 +3657,7 @@ void Item_Model_Paint(itemDef_t *item) { w = item->window.rect.w-2; h = item->window.rect.h-2; - CG_AdjustFrom640( &x, &y, &w, &h ); + DC->adjustFrom640( &x, &y, &w, &h ); refdef.x = x; refdef.y = y; @@ -4343,7 +4343,7 @@ void Menu_Paint(menuDef_t *menu, qboolean forcePaint) { } if (menu->forceScreenPlacement) { - CG_SetScreenPlacement( menu->screenHPos, menu->screenVPos ); + DC->setScreenPlacement( menu->screenHPos, menu->screenVPos ); } // draw the background if necessary @@ -4353,7 +4353,7 @@ void Menu_Paint(menuDef_t *menu, qboolean forcePaint) { DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background ); } else if (menu->window.background) { // this allows a background shader without being full screen - //CG_DrawPic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader); + //DC->drawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader); } // paint the background and or border @@ -4371,7 +4371,7 @@ void Menu_Paint(menuDef_t *menu, qboolean forcePaint) { } if (menu->forceScreenPlacement) { - CG_PopScreenPlacement(); + DC->popScreenPlacement(); } } diff --git a/code/ui/ui_shared.h b/code/ui/ui_shared.h index 3ece3bc68..b83fbf3c4 100644 --- a/code/ui/ui_shared.h +++ b/code/ui/ui_shared.h @@ -381,6 +381,9 @@ typedef struct { void (*stopCinematic)(int handle); void (*drawCinematic)(int handle, float x, float y, float w, float h); void (*runCinematicFrame)(int handle); + void (*adjustFrom640)( float *x, float *y, float *w, float *h ); + void (*setScreenPlacement)( screenPlacement_e hpos, screenPlacement_e vpos ); + void (*popScreenPlacement)( void ); int realTime; int frameTime; From b2efe17932e9752569ac73770ba35327ace66bf0 Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sat, 23 Jun 2018 07:55:29 -0500 Subject: [PATCH 16/42] mint-arena: Add capturelimit and g_instagib to callvote --- code/game/g_cmds.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/game/g_cmds.c b/code/game/g_cmds.c index b25800129..329379def 100644 --- a/code/game/g_cmds.c +++ b/code/game/g_cmds.c @@ -1410,9 +1410,11 @@ void Cmd_CallVote_f( gentity_t *ent ) { } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) { } else if ( !Q_stricmp( arg1, "timelimit" ) ) { } else if ( !Q_stricmp( arg1, "fraglimit" ) ) { + } else if ( !Q_stricmp( arg1, "capturelimit" ) ) { + } else if ( !Q_stricmp( arg1, "g_instagib" ) ) { } else { trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" ); - trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map , g_gametype , kick , kicknum , g_doWarmup, timelimit