diff --git a/Source/Client/Draw.c b/Source/Client/Draw.c index 85b3969f..67c6a84d 100755 --- a/Source/Client/Draw.c +++ b/Source/Client/Draw.c @@ -245,6 +245,7 @@ void CSQC_UpdateView( float fWinWidth, float fWinHeight, float fGameFocus ) { } HUD_DrawOrbituaries(); + HUD_DrawVoice(); CSQC_DrawChat(); // Don't even try to draw centerprints and VGUI menus when scores are shown diff --git a/Source/Client/HUD.c b/Source/Client/HUD.c index e36c444b..1c3677ec 100755 --- a/Source/Client/HUD.c +++ b/Source/Client/HUD.c @@ -442,3 +442,30 @@ void HUD_Draw( void ) { HUD_DrawProgressBar(); HUD_DrawWeaponSelect(); } + + +/* +================= +HUD_DrawVoice + +Draws a little notification for anyone using voice chat +================= +*/ +void HUD_DrawVoice( void ) { + vector vVoicePos = vVideoMins + [ vVideoResolution_x - 160, vVideoResolution_y - 136 ]; + + for ( int i = -1; i > -32; i-- ) { + if ( getplayerkeyvalue( i, INFOKEY_P_VOIPSPEAKING ) == "1" ) { + drawfill( vVoicePos, '144 24', VGUI_WINDOW_BGCOLOR, VGUI_WINDOW_BGALPHA ); + drawfill( vVoicePos, [144, 1], vVGUIColor, VGUI_WINDOW_FGALPHA ); + drawfill( [vVoicePos_x, vVoicePos_y + 23], [144, 1], vVGUIColor, VGUI_WINDOW_FGALPHA ); + drawfill( vVoicePos, [1, 24], vVGUIColor, VGUI_WINDOW_FGALPHA ); + drawfill( [vVoicePos_x + 143, vVoicePos_y], [1, 24], vVGUIColor, VGUI_WINDOW_FGALPHA ); + + CSQC_DrawText( [ vVoicePos_x + 16, vVoicePos_y + 8 ], sprintf( " %.13s", getplayerkeyvalue( i, "name" ) ), '8 8', vVGUIColor, VGUI_WINDOW_FGALPHA, DRAWFLAG_NORMAL, FONT_DEFAULT ); + + drawpic( vVoicePos + '2 0', "gfx/vgui/icntlk_sv.tga", '24 24', vVGUIColor, 1, DRAWFLAG_NORMAL ); + vVoicePos_y -= 32; + } + } +} \ No newline at end of file diff --git a/Source/Client/Init.c b/Source/Client/Init.c index 83ad95de..6e754659 100755 --- a/Source/Client/Init.c +++ b/Source/Client/Init.c @@ -70,6 +70,8 @@ void CSQC_Init(float apilevel, string enginename, float engineversion) { precache_sound( "debris/bustconcrete2.wav" ); precache_sound( "debris/bustceiling.wav" ); + precache_pic( "gfx/vgui/icntlk_sv" ); + for ( int i = 0; i < ( CS_WEAPON_COUNT - 1 ); i++ ) { precache_model( sViewModels[ i ] ); } diff --git a/Source/Client/Player.c b/Source/Client/Player.c index 608a091e..45c5a0ba 100755 --- a/Source/Client/Player.c +++ b/Source/Client/Player.c @@ -100,6 +100,8 @@ void Player_Draw( void ) { self.baseframe2time += frametime; self.frame2time += frametime; + + self.bonecontrol5 = stof( getplayerkeyvalue( player_localnum, INFOKEY_P_VOIPLOUDNESS ) ); } /* diff --git a/Source/Client/Sound.c b/Source/Client/Sound.c index 32250a5c..432a6c81 100755 --- a/Source/Client/Sound.c +++ b/Source/Client/Sound.c @@ -44,6 +44,9 @@ void Sound_PlayVOX( string sMessage ) { } void Sound_ProcessWordQue( void ) { + if ( cltime < 2 ) { + return; + } if ( iVOXCount ) { if ( fSampleTime < time ) { localcmd( sprintf( "play %s\n", sndVOX[ iVOXPos ].sSample ) ); diff --git a/Source/FreeCS-CE.prj b/Source/FreeCS-CE.prj index 73885673..6368a8b8 100644 --- a/Source/FreeCS-CE.prj +++ b/Source/FreeCS-CE.prj @@ -1,5 +1,5 @@ - + @@ -60,6 +60,7 @@ + @@ -73,7 +74,7 @@ - + diff --git a/Source/Menu/MenuConfiguration.c b/Source/Menu/MenuConfiguration.c index 42a8b459..af36547c 100755 --- a/Source/Menu/MenuConfiguration.c +++ b/Source/Menu/MenuConfiguration.c @@ -55,7 +55,12 @@ void Menu_Configuration_Init( void ) { while ( ( sTemp = fgets( fileSettings ) ) ) { // Tokenize and just parse this stuff in if ( tokenize_console( sTemp ) == 2 ) { - strActBind[ iCount ] = argv( 0 ); + // FTE uses +voip, so replace the GoldSrc bind with that + if ( argv( 0 ) != "+voicerecord" ) { + strActBind[ iCount ] = argv( 0 ); + } else { + strActBind[ iCount ] = "+voip"; + } strActDescr[ iCount ] = argv( 1 ); //print( sprintf( "%s %s\n", strActBind[ iCount ], strActDescr[ iCount ] ) ); iCount++; diff --git a/Source/Server/Client.c b/Source/Server/Client.c index 3f4115b5..9605f0a7 100755 --- a/Source/Server/Client.c +++ b/Source/Server/Client.c @@ -113,6 +113,11 @@ void PutClientInServer( void ) { // Because we don't want to reset these when we die Money_AddMoney( self, autocvar_mp_startmoney ); + if ( autocvar_sv_voxannounce == TRUE ) { + float fTimeLeft = cvar( "mp_timelimit" ) - ( time / 60 ); + Vox_Singlecast( self, sprintf( "%s minutes remaining", Vox_TimeToString( fTimeLeft ) ) ); + } + self.team = 0; forceinfokey( self, "*team", "0" ); } diff --git a/Source/Server/Defs.h b/Source/Server/Defs.h index b0c70079..b9eb139c 100755 --- a/Source/Server/Defs.h +++ b/Source/Server/Defs.h @@ -27,12 +27,12 @@ var float autocvar_mp_buytime = 90; var float autocvar_mp_freezetime = 6; var float autocvar_mp_c4timer = 45; var float autocvar_mp_roundtime = 5; -var float autocvar_mp_fillweapons = 0; var float autocvar_mp_timelimit = 60; var string autocvar_motdfile = "motd.txt"; +var int autocvar_mp_fillweapons = FALSE; var int autocvar_mp_autoreload = FALSE; - +var int autocvar_sv_voxannounce = TRUE; // Mapcycle features var string autocvar_mapcyclefile = "mapcycle.txt"; diff --git a/Source/Server/Main.c b/Source/Server/Main.c index eabc0bdc..171233e6 100755 --- a/Source/Server/Main.c +++ b/Source/Server/Main.c @@ -86,11 +86,7 @@ float ConsoleCmd( string sCommand ) { if ( argv( 0 ) == "vox" ) { localcmd( sprintf( "echo [VOX] Sending: %s\n", argv( 1 ) ) ); - WriteByte( MSG_MULTICAST, SVC_CGAMEPACKET ); - WriteByte( MSG_MULTICAST, EV_CHAT_VOX ); - WriteString( MSG_MULTICAST, argv( 1 ) ); - msg_entity = world; - multicast( '0 0 0', MULTICAST_ALL ); + Vox_Broadcast( argv( 1 ) ); return TRUE; } diff --git a/Source/Server/Timer.c b/Source/Server/Timer.c index a8024fa4..82716a65 100755 --- a/Source/Server/Timer.c +++ b/Source/Server/Timer.c @@ -47,6 +47,23 @@ Called once every frame to check the status of things ================= */ void Timer_Update( void ) { + static float fVoxTimer; + + // Not happy with this, but it'll do + if ( autocvar_sv_voxannounce == TRUE ) { + if ( fVoxTimer > time ) { + return; + } + + float fTimeLeft = ( cvar( "mp_timelimit" ) * 60 ) - time; + for ( int i = 0; i <= 10; i++ ) { + if ( rint( fTimeLeft ) == ( i * 60 ) ) { + Vox_Broadcast( sprintf( "%s minutes remaining", Vox_TimeToString( fTimeLeft / 60 ) ) ); + fVoxTimer = time + 10.0f; + } + } + } + // This map has been played enough we think if ( time >= ( cvar( "mp_timelimit" ) * 60 ) ) { for ( int i = 0; i < iMapCycleCount; i++ ) { diff --git a/Source/Server/Vox.c b/Source/Server/Vox.c new file mode 100755 index 00000000..41a56b29 --- /dev/null +++ b/Source/Server/Vox.c @@ -0,0 +1,76 @@ +/* +FreeCS Project +Copyright (C) 2016, 2017 Marco "eukara" Hladik + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +================= +Vox_TimeToString + +Assumes time in minutes. +TODO: Actually output proper, tokenized strings for not just 1-10 minutes +================= +*/ +string Vox_TimeToString( float fTime ) { + fTime = rint( fTime ); + + switch ( fTime ) { + case 0: return "no"; + case 1: return "one"; + case 2: return "two"; + case 3: return "three"; + case 4: return "four"; + case 5: return "five"; + case 6: return "six"; + case 7: return "seven"; + case 8: return "eight"; + case 9: return "nine"; + case 10: return "ten"; + default: return "over ten"; + } +} + +/* +================= +Vox_Broadcast + +Broadcasts a VOX message to all players +================= +*/ +void Vox_Broadcast( string sMessage ) { + WriteByte( MSG_MULTICAST, SVC_CGAMEPACKET ); + WriteByte( MSG_MULTICAST, EV_CHAT_VOX ); + WriteString( MSG_MULTICAST, sMessage ); + msg_entity = world; + multicast( '0 0 0', MULTICAST_ALL ); +} + +/* +================= +Vox_Singlecast + +Broadcasts a VOX message to one player +================= +*/ +void Vox_Singlecast( entity eClient, string sMessage ) { + WriteByte( MSG_MULTICAST, SVC_CGAMEPACKET ); + WriteByte( MSG_MULTICAST, EV_CHAT_VOX ); + WriteString( MSG_MULTICAST, sMessage ); + msg_entity = eClient; + multicast( '0 0 0', MULTICAST_ONE_R ); +} \ No newline at end of file diff --git a/Source/Server/progs.src b/Source/Server/progs.src index 96617012..e8d0bebe 100755 --- a/Source/Server/progs.src +++ b/Source/Server/progs.src @@ -46,6 +46,7 @@ PhysicsMove.c ../Shared/Effects.c ../Shared/Equipment.c +Vox.c Ammo.c Damage.c TraceAttack.c diff --git a/Source/Shared/Equipment.c b/Source/Shared/Equipment.c index cefb2e28..56f01291 100755 --- a/Source/Shared/Equipment.c +++ b/Source/Shared/Equipment.c @@ -104,7 +104,7 @@ void CSEv_PlayerBuyEquipment_f( float fID ) { self.armor = 100; Money_AddMoney( self, -650 ); sound( self, CHAN_ITEM, "items/tr_kevlar.wav", 1, ATTN_IDLE ); - centerprint( self, "You already have a helmet,\nand now you're bought some kevlar!" ); + centerprint( self, "You already have a helmet,\nand now you've bought some kevlar!" ); } else { // Get both self.armor = 100; diff --git a/Source/Shared/WeaponC4Bomb.c b/Source/Shared/WeaponC4Bomb.c index 4056af9a..c4e4e74c 100755 --- a/Source/Shared/WeaponC4Bomb.c +++ b/Source/Shared/WeaponC4Bomb.c @@ -103,7 +103,7 @@ static void WeaponC4BOMB_Use( void ) { static void WeaponC4BOMB_Think( void ) { // If the guy who started using us stopped using us, reset the defuser counter - if ( ( self.eUser != world ) && ( self.eUser.button6 == FALSE ) ) { + if ( ( self.eUser != world ) && ( self.eUser.button3 == FALSE ) ) { self.eUser.fProgressBar = 0; self.eUser = world; fDefuseProgress = 0; @@ -159,7 +159,7 @@ static void WeaponC4BOMB_Think( void ) { } } -void WeaponC4BOMB_Drop( vector vBombPos ) { +void WeaponC4BOMB_Drop( vector vBombPos, vector vNormal ) { // Do all the dirty entspawning stuff entity eBomb = spawn(); eBomb.classname = "c4bomb"; @@ -173,7 +173,14 @@ void WeaponC4BOMB_Drop( vector vBombPos ) { eBomb.fAttackFinished = time + autocvar_mp_c4timer; eBomb.vUse = WeaponC4BOMB_Use; eBomb.iUsable = TRUE; - eBomb.owner = world; + eBomb.owner = self; + + // Align the bomb to the wall + vector vBombAngles = self.angles + '0 90 0'; + vBombAngles_x *= -1; + makevectors( vBombAngles ); + vector vCoplanar = v_forward - ( v_forward * vNormal ) * vNormal; + eBomb.angles = vectoangles( vCoplanar, vNormal ); sound( eBomb, CHAN_WEAPON, "weapons/c4_plant.wav", 1.0, ATTN_IDLE ); diff --git a/Source/Shared/WeaponGlock18.c b/Source/Shared/WeaponGlock18.c index 6e3dbb94..1ca06233 100755 --- a/Source/Shared/WeaponGlock18.c +++ b/Source/Shared/WeaponGlock18.c @@ -89,15 +89,19 @@ void WeaponGLOCK18_PrimaryFire( void ) { sound( self, CHAN_WEAPON, "weapons/glock18-2.wav", 1, ATTN_NORM ); } } else { - if ( (self.iMag_GLOCK18 - 3 ) < 0 ) { - return FALSE; + if ( self.iMag_GLOCK18 <= 0 ) { + return; } - BaseGun_AccuracyCalc(); - TraceAttack_FireBullets( 3, ( self.origin + self.view_ofs ) ); - self.iMag_GLOCK18 -= 3; + for ( int i = 0; i < 3; i++ ) { + if ( self.iMag_GLOCK18 ) { + BaseGun_ShotMultiplierHandle( 1 ); + BaseGun_AccuracyCalc(); + TraceAttack_FireBullets( 1, ( self.origin + self.view_ofs ) ); + self.iMag_GLOCK18 -= 1; + } + } self.fAttackFinished = time + 0.5; - sound( self, CHAN_WEAPON, "weapons/glock18-1.wav", 1, ATTN_NORM ); Client_SendEvent( self, EV_WEAPON_PRIMARYATTACK ); BaseGun_ShotMultiplierHandle( 3 ); diff --git a/Source/Shared/Weapons.c b/Source/Shared/Weapons.c index 7b350a46..c010782f 100755 --- a/Source/Shared/Weapons.c +++ b/Source/Shared/Weapons.c @@ -46,7 +46,7 @@ string sWeaponModels[ CS_WEAPON_COUNT ] = { "models/w_g3sg1.mdl", "models/w_sg550.mdl", "models/w_m249.mdl", - "models/w_c4.mdl", + "models/w_backpack.mdl", "models/w_flashbang.mdl", "models/w_hegrenade.mdl", "models/w_smokegrenade.mdl" diff --git a/freecs/csprogs.dat b/freecs/csprogs.dat index 80d6bf7d..b6ede5f6 100644 Binary files a/freecs/csprogs.dat and b/freecs/csprogs.dat differ diff --git a/freecs/menu.dat b/freecs/menu.dat index b4674ff8..475cce81 100755 Binary files a/freecs/menu.dat and b/freecs/menu.dat differ diff --git a/freecs/progs.dat b/freecs/progs.dat index 4e8e4e0d..a7dacf2d 100644 Binary files a/freecs/progs.dat and b/freecs/progs.dat differ