diff --git a/CHANGELOG.md b/CHANGELOG.md index 1117dcce..eaf35388 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * `g_harvesterFromBodies`: In Harvester matches, skulls now spawn from dead bodies (a la [UT3!Greed](https://antifandom.com/unreal/wiki/Greed)) rather than a skull receptacle in the middle of the arena. Allows Harvester matches to take place in maps that don't feature a skull receptacle. **Default: 0.** * `g_ddCaptureTime` and `g_ddRespawnDelay`: New cvars for Double Domination that control the amount of holding time to score and the waiting time before a new round starts. **Default for both: 10.** * `bot_developer`: Bitflag that enables bot-based feedback such as action report (`&1`), regular chat disabling (`&2`) and obstacle feedback (`&4`). **Default: 0.** + * `g_weaponArena` and `g_weaponArenaWeapon`: two cvars that replace and extend `g_rockets` in order to be able to use `g_rockets` with every weapon other than rockets. * Shuffle has been reworked by implementing the solution from Aftershock. * New commands: * `weapbest`: Selects the best weapon. @@ -36,6 +37,9 @@ * Tons of other bug fixes. ### Extended version +* New cvars that replace `g_rockets`: `g_weaponArena` and `g_weaponArenaWeapon`. + * `g_weaponArena` enables the "Weapon Arena" mode, which is the old g_rockets, but with any other weapon. `g_weaponArena 2` adds the Grappling Hook to the inventory. + * `g_weaponArenaWeapon` controls, via specific strings, which weapon it's spawned with its ammo boxes. The weapon cannot be picked up via menu, only (for now) via console. The full string list can be locate [here](https://github.com/OpenArena/gamecode/pull/171). * New cvar: bot_developer, for bot-based debugging. * Missionpack/UI3 backend refactors. * "You Have Been Mined" message outright displays the counter instead of delaying it. diff --git a/code/cgame/cg_servercmds.c b/code/cgame/cg_servercmds.c index a309c3e0..47fad786 100644 --- a/code/cgame/cg_servercmds.c +++ b/code/cgame/cg_servercmds.c @@ -362,7 +362,7 @@ void CG_ParseServerinfo( void ) { cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) ); cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); cgs.roundtime = atoi( Info_ValueForKey( info, "elimination_roundtime" ) ); - cgs.nopickup = atoi( Info_ValueForKey( info, "g_rockets" ) ) + atoi( Info_ValueForKey( info, "g_instantgib" ) ) + atoi( Info_ValueForKey( info, "g_elimination" ) ); + cgs.nopickup = atoi( Info_ValueForKey( info, "g_weaponArena" ) ) + atoi( Info_ValueForKey( info, "g_instantgib" ) ) + atoi( Info_ValueForKey( info, "g_elimination" ) ); cgs.lms_mode = atoi( Info_ValueForKey( info, "g_lms_mode" ) ); cgs.altExcellent = atoi( Info_ValueForKey( info, "g_altExcellent" ) ); mapname = Info_ValueForKey( info, "mapname" ); diff --git a/code/game/ai_dmq3.c b/code/game/ai_dmq3.c index ca5fa5e7..431e9b56 100644 --- a/code/game/ai_dmq3.c +++ b/code/game/ai_dmq3.c @@ -1782,8 +1782,8 @@ void BotChooseWeapon(bot_state_t *bs) { } else { if (g_instantgib.integer) newweaponnum = WP_RAILGUN; - else if (g_rockets.integer) - newweaponnum = WP_ROCKET_LAUNCHER; + else if (g_weaponArena.integer) + newweaponnum = G_GetWeaponArena(g_weaponArenaWeapon.string); else newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory); if (bs->weaponnum != newweaponnum) bs->weaponchange_time = FloatTime(); diff --git a/code/game/ai_main.c b/code/game/ai_main.c index 65c35f49..9ddaafb2 100644 --- a/code/game/ai_main.c +++ b/code/game/ai_main.c @@ -187,7 +187,7 @@ int BotAI_GetEntityState( int entityNum, entityState_t *state ) { memset( state, 0, sizeof(entityState_t) ); if (!ent->inuse) return qfalse; if (!ent->r.linked) return qfalse; - if ( !(G_IsARoundBasedGametype(g_gametype.integer) ||g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer) + if ( !(G_IsARoundBasedGametype(g_gametype.integer) ||g_instantgib.integer || g_weaponArena.integer || g_elimination_allgametypes.integer) && (ent->r.svFlags & SVF_NOCLIENT) ) { return qfalse; } @@ -1535,7 +1535,7 @@ int BotAIStartFrame(int time) { trap_BotLibUpdateEntity(i, NULL); continue; } - if ( !(G_IsARoundBasedGametype(g_gametype.integer) ||g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer) + if ( !(G_IsARoundBasedGametype(g_gametype.integer) ||g_instantgib.integer || g_weaponArena.integer || g_elimination_allgametypes.integer) && ent->r.svFlags & SVF_NOCLIENT) { trap_BotLibUpdateEntity(i, NULL); continue; diff --git a/code/game/g_client.c b/code/game/g_client.c index f1b5cd89..2a47ce8a 100644 --- a/code/game/g_client.c +++ b/code/game/g_client.c @@ -1,5 +1,5 @@ /* -=========================================================================== +===========================================================================weaponarena Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. @@ -1860,12 +1860,16 @@ void ClientSpawn(gentity_t *ent) { } } - if (g_rockets.integer) { - client->ps.stats[STAT_WEAPONS] = ( 1 << WP_ROCKET_LAUNCHER ); - client->ps.ammo[WP_ROCKET_LAUNCHER] = 999; + if (g_weaponArena.integer) { + client->ps.stats[STAT_WEAPONS] |= ( 1 << G_GetWeaponArena(g_weaponArenaWeapon.string) ); + if (G_GetWeaponArena(g_weaponArenaWeapon.string) == WP_GAUNTLET) { + client->ps.ammo[G_GetWeaponArena(g_weaponArenaWeapon.string)] = -1; + } else { + client->ps.ammo[G_GetWeaponArena(g_weaponArenaWeapon.string)] = 999; + } } - if (g_grapple.integer) { + if (g_grapple.integer || (g_weaponArena.integer > 1)) { client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRAPPLING_HOOK ); } diff --git a/code/game/g_combat.c b/code/game/g_combat.c index bfb8347f..312db712 100644 --- a/code/game/g_combat.c +++ b/code/game/g_combat.c @@ -133,7 +133,7 @@ void TossClientItems( gentity_t *self ) } } - if (g_instantgib.integer || g_rockets.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer) { + if (g_instantgib.integer || g_weaponArena.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer) { //Nothing! } else if ( weapon > WP_MACHINEGUN && weapon != WP_GRAPPLING_HOOK && diff --git a/code/game/g_items.c b/code/game/g_items.c index 25cbdcca..8cb8235b 100644 --- a/code/game/g_items.c +++ b/code/game/g_items.c @@ -430,7 +430,7 @@ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) qboolean predict; //instant gib - if ((g_instantgib.integer || g_rockets.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer) + if ((g_instantgib.integer || g_weaponArena.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer) && ent->item->giType != IT_TEAM) return; @@ -741,7 +741,7 @@ void FinishSpawningItem( gentity_t *ent ) // powerups don't spawn in for a while (but not in elimination) - if(!G_IsARoundBasedGametype(g_gametype.integer) && !g_instantgib.integer && !g_elimination_allgametypes.integer && !g_rockets.integer ) + if(!G_IsARoundBasedGametype(g_gametype.integer) && !g_instantgib.integer && !g_elimination_allgametypes.integer && !g_weaponArena.integer ) if ( ent->item->giType == IT_POWERUP ) { float respawn; @@ -858,8 +858,8 @@ void ClearRegisteredItems( void ) } RegisterItem( BG_FindItemForWeapon( WP_RAILGUN ) ); } - else if(g_rockets.integer) { - RegisterItem( BG_FindItemForWeapon( WP_ROCKET_LAUNCHER ) ); + else if(g_weaponArena.integer) { + RegisterItem( BG_FindItemForWeapon(G_GetWeaponArena(g_weaponArenaWeapon.string))); } else { // players always start with the base weapon @@ -996,7 +996,7 @@ void G_SpawnItem (gentity_t *ent, gitem_t *item) ent->physicsBounce = 0.50; // items are bouncy if (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS || - ( item->giType != IT_TEAM && (g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer || g_gametype.integer==GT_CTF_ELIMINATION) ) ) { + ( item->giType != IT_TEAM && (g_instantgib.integer || g_weaponArena.integer || g_elimination_allgametypes.integer || g_gametype.integer==GT_CTF_ELIMINATION) ) ) { ent->s.eFlags |= EF_NODRAW; //Invisible in elimination ent->r.svFlags |= SVF_NOCLIENT; //Don't broadcast } diff --git a/code/game/g_local.h b/code/game/g_local.h index 64aa824d..6601e1c7 100644 --- a/code/game/g_local.h +++ b/code/game/g_local.h @@ -1116,7 +1116,8 @@ extern vmCvar_t g_elimination_mine; extern vmCvar_t g_elimination_nail; //If lockspectator: 0=no limit, 1 = cannot follow enemy, 2 = must follow friend extern vmCvar_t g_elimination_lockspectator; -extern vmCvar_t g_rockets; +extern vmCvar_t g_weaponArena; +extern vmCvar_t g_weaponArenaWeapon; //new in elimination Beta2 extern vmCvar_t g_instantgib; extern vmCvar_t g_vampire; @@ -1432,4 +1433,5 @@ qboolean G_IsATeamGametype(int check); /* Whether the gametype is team-based or qboolean G_UsesTeamFlags(int check); /* Whether the gametype uses the red and blue flags. */ qboolean G_UsesTheWhiteFlag(int check); /* Whether the gametype uses the neutral flag. */ qboolean G_IsARoundBasedGametype(int check); /* Whether the gametype uses the neutral flag. */ +int G_GetWeaponArena(char* cvarWaString); /* Takes a string and returns the value of a weapon. */ /* /Neon_Knight */ diff --git a/code/game/g_main.c b/code/game/g_main.c index 90a5dc7a..c0d1bd25 100644 --- a/code/game/g_main.c +++ b/code/game/g_main.c @@ -130,7 +130,8 @@ vmCvar_t g_elimination_chain; vmCvar_t g_elimination_mine; vmCvar_t g_elimination_nail; vmCvar_t g_elimination_lockspectator; -vmCvar_t g_rockets; +vmCvar_t g_weaponArena; +vmCvar_t g_weaponArenaWeapon; //dmn_clowns suggestions (with my idea of implementing): vmCvar_t g_instantgib; vmCvar_t g_vampire; @@ -351,7 +352,8 @@ static cvarTable_t gameCvarTable[] = { //nexuiz style rocket arena - { &g_rockets, "g_rockets", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse }, + { &g_weaponArena, "g_weaponArena", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse }, + { &g_weaponArenaWeapon, "g_weaponArenaWeapon", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse }, //Instantgib and Vampire thingies { &g_instantgib, "g_instantgib", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse }, @@ -636,7 +638,7 @@ void G_UpdateCvars( void ) VoteParseCustomVotes(); //Here comes the cvars that must trigger a map_restart - if (cv->vmCvar == &g_instantgib || cv->vmCvar == &g_rockets || cv->vmCvar == &g_elimination_allgametypes) { + if (cv->vmCvar == &g_instantgib || cv->vmCvar == &g_weaponArena || cv->vmCvar == &g_elimination_allgametypes) { trap_Cvar_Set("sv_dorestart","1"); } @@ -759,7 +761,7 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) //disable unwanted cvars if( g_gametype.integer == GT_SINGLE_PLAYER ) { g_instantgib.integer = 0; - g_rockets.integer = 0; + g_weaponArena.integer = 0; g_vampire.value = 0.0f; } @@ -2877,4 +2879,52 @@ Checks if the gametype has a round-based system. qboolean G_IsARoundBasedGametype(int check) { return GAMETYPE_IS_ROUND_BASED(check); } -/* /Neon_Knight */ \ No newline at end of file +/* +=================== +G_GetWeaponArena + +Returns the value of a weapon for g_weaponArena. +=================== + */ +int G_GetWeaponArena(char* cvarWaString) { + if (strcmp(cvarWaString,"mg") || strcmp(cvarWaString,"machinegun") || + strcmp(cvarWaString,"machine gun") || strcmp(cvarWaString,"2")) + return WP_MACHINEGUN; + if (strcmp(cvarWaString,"sg") || strcmp(cvarWaString,"shotgun") || + strcmp(cvarWaString,"shot gun") || strcmp(cvarWaString,"3")) + return WP_SHOTGUN; + if (strcmp(cvarWaString,"gl") || strcmp(cvarWaString,"grenade") || + strcmp(cvarWaString,"grenade launcher") || strcmp(cvarWaString,"grenadelauncher") || + strcmp(cvarWaString,"4")) + return WP_GRENADE_LAUNCHER; + if (strcmp(cvarWaString,"rl") || strcmp(cvarWaString,"rocket") || + strcmp(cvarWaString,"rocket launcher") || strcmp(cvarWaString,"rocketlauncher") || + strcmp(cvarWaString,"5")) + return WP_ROCKET_LAUNCHER; + if (strcmp(cvarWaString,"lg") || strcmp(cvarWaString,"lightning") || + strcmp(cvarWaString,"lightning gun") || strcmp(cvarWaString,"lightninggun") || + strcmp(cvarWaString,"6")) + return WP_LIGHTNING; + if (strcmp(cvarWaString,"rg") || strcmp(cvarWaString,"railgun") || + strcmp(cvarWaString,"rail gun") || strcmp(cvarWaString,"7")) + return WP_RAILGUN; + if (strcmp(cvarWaString,"pg") || strcmp(cvarWaString,"plasma") || + strcmp(cvarWaString,"plasma gun") || strcmp(cvarWaString,"plasmagun") || + strcmp(cvarWaString,"8")) + return WP_PLASMAGUN; + if (strcmp(cvarWaString,"bfg") || strcmp(cvarWaString,"big fairie gun") || + strcmp(cvarWaString,"big freakin gun") || strcmp(cvarWaString,"9")) + return WP_BFG; + if (strcmp(cvarWaString,"ng") || strcmp(cvarWaString,"nailgun") || + strcmp(cvarWaString,"nail gun") || strcmp(cvarWaString,"11")) + return WP_NAILGUN; + if (strcmp(cvarWaString,"pl") || strcmp(cvarWaString,"prox") || + strcmp(cvarWaString,"mines") || strcmp(cvarWaString,"prox launcher") || + strcmp(cvarWaString,"proxlauncher") || strcmp(cvarWaString,"12")) + return WP_PROX_LAUNCHER; + if (strcmp(cvarWaString,"cg") || strcmp(cvarWaString,"chaingun") || + strcmp(cvarWaString,"chain gun") || strcmp(cvarWaString,"13")) + return WP_CHAINGUN; + return WP_GAUNTLET; +} +/* /Neon_Knight */ diff --git a/code/q3_ui/ui_startserver.c b/code/q3_ui/ui_startserver.c index 877cf91e..cae5dd59 100644 --- a/code/q3_ui/ui_startserver.c +++ b/code/q3_ui/ui_startserver.c @@ -801,7 +801,7 @@ typedef struct { menulist_s pmove; menuradiobutton_s oneway; menuradiobutton_s instantgib; - menuradiobutton_s rockets; + menuradiobutton_s weaponArena; menulist_s lmsMode; menulist_s botSkill; @@ -905,7 +905,7 @@ static void ServerOptions_Start( void ) { int pmove; int lan; int instantgib; - int rockets; + int weaponArena; int oneway; int lmsMode; int skill; @@ -922,7 +922,7 @@ static void ServerOptions_Start( void ) { lan = s_serveroptions.lan.curvalue; pmove = s_serveroptions.pmove.curvalue; instantgib = s_serveroptions.instantgib.curvalue; - rockets = s_serveroptions.rockets.curvalue; + weaponArena = s_serveroptions.weaponArena.curvalue; oneway = s_serveroptions.oneway.curvalue; //Sago: For some reason you need to add 1 to curvalue to get the UI to show the right thing (fixed?) lmsMode = s_serveroptions.lmsMode.curvalue; //+1; @@ -1025,7 +1025,7 @@ static void ServerOptions_Start( void ) { trap_Cvar_SetValue( "sv_pure", pure ); trap_Cvar_SetValue( "sv_lanForceRate", lan ); trap_Cvar_SetValue( "g_instantgib", instantgib ); - trap_Cvar_SetValue( "g_rockets", rockets ); + trap_Cvar_SetValue( "g_weaponArena", weaponArena ); trap_Cvar_SetValue( "g_lms_mode", lmsMode); trap_Cvar_SetValue( "elimination_ctf_oneway", oneway ); switch(pmove) { @@ -1248,11 +1248,11 @@ static void ServerOptions_StatusBar_Instantgib( void* ptr ) { /* ================= -ServerOptions_StatusBar_Allrockets +ServerOptions_StatusBar_WeaponArena ================= */ -static void ServerOptions_StatusBar_Allrockets( void* ptr ) { - UI_DrawString( 320, 440, "Only Rocket launcher with Inf. ammo", UI_CENTER|UI_SMALLFONT, colorWhite ); +static void ServerOptions_StatusBar_WeaponArena( void* ptr ) { + UI_DrawString( 320, 440, "Only allows the selected weapon with all its ammo", UI_CENTER|UI_SMALLFONT, colorWhite ); } /* @@ -1536,7 +1536,7 @@ static void ServerOptions_SetMenuItems( void ) { s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_pure" ) ); s_serveroptions.lan.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_lanforcerate" ) ); s_serveroptions.instantgib.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_instantgib" ) ); - s_serveroptions.rockets.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_rockets" ) ); + s_serveroptions.weaponArena.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_weaponArena" ) ); s_serveroptions.lmsMode.curvalue = Com_Clamp( 0, 3, trap_Cvar_VariableValue("g_lms_mode") ); s_serveroptions.oneway.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "elimination_ctf_oneway" ) ); s_serveroptions.pmove.curvalue = 0; @@ -1738,14 +1738,14 @@ static void ServerOptions_MenuInit( qboolean multiplayer ) { s_serveroptions.instantgib.generic.name = "Instantgib:"; s_serveroptions.instantgib.generic.statusbar = ServerOptions_StatusBar_Instantgib; - //Rockets option + //Weapon Arena option y += BIGCHAR_HEIGHT+2; - s_serveroptions.rockets.generic.type = MTYPE_RADIOBUTTON; - s_serveroptions.rockets.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; - s_serveroptions.rockets.generic.x = OPTIONS_X; - s_serveroptions.rockets.generic.y = y; - s_serveroptions.rockets.generic.name = "All rockets:"; - s_serveroptions.rockets.generic.statusbar = ServerOptions_StatusBar_Allrockets; + s_serveroptions.weaponArena.generic.type = MTYPE_RADIOBUTTON; + s_serveroptions.weaponArena.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.weaponArena.generic.x = OPTIONS_X; + s_serveroptions.weaponArena.generic.y = y; + s_serveroptions.weaponArena.generic.name = "Weapon Arena:"; + s_serveroptions.weaponArena.generic.statusbar = ServerOptions_StatusBar_WeaponArena; if( s_serveroptions.gametype == GT_LMS ) { y += BIGCHAR_HEIGHT+2; @@ -1898,7 +1898,7 @@ static void ServerOptions_MenuInit( qboolean multiplayer ) { } Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure ); Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.instantgib ); - Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.rockets ); + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.weaponArena ); if( s_serveroptions.gametype == GT_LMS) { Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.lmsMode ); } diff --git a/code/ui/ui_main.c b/code/ui/ui_main.c index f008921b..e134bb01 100644 --- a/code/ui/ui_main.c +++ b/code/ui/ui_main.c @@ -4044,8 +4044,10 @@ static void UI_StartSkirmish(void) trap_Cvar_Set("ui_ddRespawnDelay", va("%i", temp)); temp = trap_Cvar_VariableValue( "g_obeliskHealth" ); trap_Cvar_Set("ui_obeliskHealth", va("%i", temp)); - temp = trap_Cvar_VariableValue( "g_rockets" ); - trap_Cvar_Set("ui_rockets", va("%i", temp)); + temp = trap_Cvar_VariableValue( "g_weaponArena" ); + trap_Cvar_Set("ui_weaponArena", va("%i", temp)); + temp = trap_Cvar_VariableValue( "g_weaponArenaWeapon" ); + trap_Cvar_Set("ui_weaponArenaWeapon", va("%i", temp)); temp = trap_Cvar_VariableValue( "g_gravityModifier" ); trap_Cvar_Set("ui_gravityModifier", va("%i", temp)); temp = trap_Cvar_VariableValue( "elimination_ctf_oneway" );